Commit 3b625254 authored by Dainis Abols's avatar Dainis Abols
Browse files

Remade into custom caching system

v4.0.3
parent 2c30ea0e
...@@ -5,7 +5,7 @@ namespace Lu\LuNabamusic\Controller; ...@@ -5,7 +5,7 @@ namespace Lu\LuNabamusic\Controller;
use Lu\LuNabamusic\Domain\Model\Play; use Lu\LuNabamusic\Domain\Model\Play;
use Lu\LuNabamusic\Domain\Model\Top; use Lu\LuNabamusic\Domain\Model\Top;
use Lu\LuNabamusic\Domain\Repository\SongRepository; use Lu\LuNabamusic\Domain\Repository\SongRepository;
use TYPO3\CMS\Core\Cache\CacheManager; use Lu\LuNabamusic\Helpers\CacheHelper;
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
use TYPO3\CMS\Core\FormProtection\FormProtectionFactory; use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
use TYPO3\CMS\Core\Page\PageRenderer; use TYPO3\CMS\Core\Page\PageRenderer;
...@@ -94,7 +94,7 @@ class FrontController extends ActionController ...@@ -94,7 +94,7 @@ class FrontController extends ActionController
// Preset used variables // Preset used variables
$playModel = new Play(); $playModel = new Play();
$swap = $this->settings['pluginType'] ?? ''; $swap = $this->settings['pluginType'] ?? '';
$cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_naba_top'); $cacheHelper = new CacheHelper();
$data = []; $data = [];
// Swap view types @TODO Make data gather to methods! // Swap view types @TODO Make data gather to methods!
...@@ -148,7 +148,7 @@ class FrontController extends ActionController ...@@ -148,7 +148,7 @@ class FrontController extends ActionController
]; ];
} else { } else {
$data['mostPlayedSongs'] = [ $data['mostPlayedSongs'] = [
'songs' => $cache->get('most_played_songs') ?: $playModel->getMostPlayedSongs($limit), 'songs' => $cacheHelper->get('most_played_songs') ?: $playModel->getMostPlayedSongs($limit),
]; ];
} }
...@@ -179,7 +179,7 @@ class FrontController extends ActionController ...@@ -179,7 +179,7 @@ class FrontController extends ActionController
]; ];
} else { } else {
$data['mostPlayedSongs'] = [ $data['mostPlayedSongs'] = [
'songs' => $cache->get('todays_songs') ?: $playModel->getTodaysSongs(), 'songs' => $cacheHelper->get('todays_songs') ?: $playModel->getTodaysSongs(),
]; ];
} }
...@@ -207,14 +207,14 @@ class FrontController extends ActionController ...@@ -207,14 +207,14 @@ class FrontController extends ActionController
*/ */
private function getTopSongs() private function getTopSongs()
{ {
$cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_naba_top'); $cacheHelper = new CacheHelper();
$data = $cache->get('naba_top_'.$this->settings['songsInTop']); $data = $cacheHelper->get('naba_top_'.$this->settings['songsInTop']);
$UriBuilder = $this->controllerContext->getUriBuilder()->reset()->setCreateAbsoluteUri(true); $UriBuilder = $this->controllerContext->getUriBuilder()->reset()->setCreateAbsoluteUri(true);
// If songs list is not cached do it now // If songs list is not cached do it now
if(!$data) { if(!$data) {
GeneralUtility::makeInstance(Top::class)->executeCron(); GeneralUtility::makeInstance(Top::class)->executeCron();
$data = $cache->get('naba_top_'.$this->settings['songsInTop']); $data = $cacheHelper->get('naba_top_'.$this->settings['songsInTop']);
} }
foreach ($data['songs'] as $key => $item) { foreach ($data['songs'] as $key => $item) {
......
...@@ -108,6 +108,9 @@ class Play extends AbstractEntity ...@@ -108,6 +108,9 @@ class Play extends AbstractEntity
// Call song fetch option and fail if none available! // Call song fetch option and fail if none available!
$apiSong = $this->fetchLiveEntry(); $apiSong = $this->fetchLiveEntry();
if (empty($apiSong)) { if (empty($apiSong)) {
// Update last song end time
$this->addEndTime();
return false; return false;
} }
...@@ -136,6 +139,9 @@ class Play extends AbstractEntity ...@@ -136,6 +139,9 @@ class Play extends AbstractEntity
// Check if song has changed // Check if song has changed
if ($apiSong['artist'] != $lastSong['artist'] && $apiSong['artist'] != $lastSong['artist']) { if ($apiSong['artist'] != $lastSong['artist'] && $apiSong['artist'] != $lastSong['artist']) {
// Update last song end time
$this->addEndTime();
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName); $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
$affectedRows = $queryBuilder $affectedRows = $queryBuilder
->insert($this->tableName) ->insert($this->tableName)
...@@ -145,6 +151,7 @@ class Play extends AbstractEntity ...@@ -145,6 +151,7 @@ class Play extends AbstractEntity
'title' => $apiSong['title'], 'title' => $apiSong['title'],
'first' => $firstTime, 'first' => $firstTime,
'time' => $currentTime, 'time' => $currentTime,
'endtime' => 0,
'prev' => $previousTime, 'prev' => $previousTime,
'checked' => 1, 'checked' => 1,
'cron' => 1, 'cron' => 1,
...@@ -191,12 +198,12 @@ class Play extends AbstractEntity ...@@ -191,12 +198,12 @@ class Play extends AbstractEntity
// If entry found, assign the name // If entry found, assign the name
while ($data = $programmResults->fetch()) { while ($data = $programmResults->fetch()) {
$timeZone = date_default_timezone_get();
$newCDate = new \DateTime(); $newCDate = new \DateTime();
$newSDate = new \DateTime("@{$row['start_date']}", new \DateTimeZone('UTC')); $newSDate = DateTime::createFromFormat('Y-m-d', $row['start_date'], new \DateTimeZone('UTC'));
$newSDate->setTimeZone(new \DateTimeZone($timeZone)); $newEDate = new DateTime('today');
$newEDate = new \DateTime("@{$row['end_date']}", new \DateTimeZone('UTC')); if (!empty($row['end_date'])) {
$newEDate->setTimeZone(new \DateTimeZone($timeZone)); $newEDate = DateTime::createFromFormat('Y-m-d', $row['end_date'], new \DateTimeZone('UTC'));
}
// Check if day of week matches // Check if day of week matches
if ($newSDate->format('w') <= $newCDate->format('w') && $newCDate->format('w') <= $newEDate->format('w')) { if ($newSDate->format('w') <= $newCDate->format('w') && $newCDate->format('w') <= $newEDate->format('w')) {
...@@ -233,6 +240,11 @@ class Play extends AbstractEntity ...@@ -233,6 +240,11 @@ class Play extends AbstractEntity
$cachedSong = $currentSong; $cachedSong = $currentSong;
} }
// If last song has ended return programme title
if ($cachedSong['endtime'] != 0) {
return $this->getCurrentProgramme();
}
// Check if one-line return requested // Check if one-line return requested
if ($onLine) { if ($onLine) {
return $cachedSong['artist']." - ".$cachedSong['title']; return $cachedSong['artist']." - ".$cachedSong['title'];
...@@ -423,4 +435,27 @@ class Play extends AbstractEntity ...@@ -423,4 +435,27 @@ class Play extends AbstractEntity
// Fetch config // Fetch config
$this->conf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('lu_nabamusic'); $this->conf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('lu_nabamusic');
} }
/**
* Add end time to last played song
*/
private function addEndTime()
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->tableName)->createQueryBuilder();
// Get last song uid
$queryBuilder->select('*')->orderBy('uid', 'DESC')->from($this->tableName)->setMaxResults(1);
$statement = $queryBuilder->execute();
$queryBuilder->update($this->tableName)
->where(
$queryBuilder->expr()->eq('uid', $statement->fetch()['uid'])
)
->andWhere(
$queryBuilder->expr()->eq('endtime', 0)
)
->set('endtime', time())
->execute();
}
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace Lu\LuNabamusic\Domain\Model; namespace Lu\LuNabamusic\Domain\Model;
use Lu\LuNabamusic\Domain\Repository\SongRepository; use Lu\LuNabamusic\Domain\Repository\SongRepository;
use Lu\LuNabamusic\Helpers\CacheHelper;
use Lu\LuNabamusic\Interfaces\TableView; use Lu\LuNabamusic\Interfaces\TableView;
use TYPO3\CMS\Core\Cache\CacheManager; use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
...@@ -102,22 +103,22 @@ class Top extends AbstractEntity implements TableView ...@@ -102,22 +103,22 @@ class Top extends AbstractEntity implements TableView
public function executeCron() public function executeCron()
{ {
$objectManager = GeneralUtility::makeInstance(ObjectManager::class); $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
$cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_naba_top');
$songRepository = $objectManager->get(SongRepository::class); $songRepository = $objectManager->get(SongRepository::class);
$querySettings = $objectManager->get(Typo3QuerySettings::class); $querySettings = $objectManager->get(Typo3QuerySettings::class);
$config = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('lu_nabamusic'); $config = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('lu_nabamusic');
$cacheHelper = new CacheHelper();
$querySettings->setStoragePageIds([$config['top10StorageId']]); $querySettings->setStoragePageIds([$config['top10StorageId']]);
$songRepository->setDefaultQuerySettings($querySettings); $songRepository->setDefaultQuerySettings($querySettings);
$cache->set('naba_top_10', $this->buildSongList($songRepository, 10), [], $config['cacheTime']); $cacheHelper->set('naba_top_10', $this->buildSongList($songRepository, 10));
$querySettings->setStoragePageIds([$config['top25StorageId']]); $querySettings->setStoragePageIds([$config['top25StorageId']]);
$songRepository->setDefaultQuerySettings($querySettings); $songRepository->setDefaultQuerySettings($querySettings);
$cache->set('naba_top_25', $this->buildSongList($songRepository, 25), [], $config['cacheTime']); $cacheHelper->set('naba_top_25', $this->buildSongList($songRepository, 25));
$playModel = new Play(); $playModel = new Play();
$cache->set('todays_songs', $playModel->getTodaysSongs(), [], $config['cacheTime']); $cacheHelper->set('todays_songs', $playModel->getTodaysSongs());
$cache->set('most_played_songs', $playModel->getMostPlayedSongs(50), [], $config['cacheTime']); $cacheHelper->set('most_played_songs', $playModel->getMostPlayedSongs(50));
return true; return true;
} }
......
<?php
namespace Lu\LuNabamusic\Helpers;
/**
* Class CacheHelper
*
* @author Lauris Karklis <lauris,karklis@lu.lv>
* @owner University of Latvia
* @since 14.07.2021
*
* @package Lu\LuNabamusic\Helpers
*/
class CacheHelper
{
/**
* Table name
*
* @var string
*/
private $tableName = 'tx_lunabamusic_cache';
/**
* DB configuration
*
* @var mixed
*/
private $config;
/**
* PDO DB connector
*
* @var \PDO
*/
private \PDO $db;
/**
* CacheHelper constructor.
*/
public function __construct()
{
$this->config = require '/home/portal/typo3/typo3conf/LocalConfiguration.php';
$this->db = new \PDO(
'mysql:host='.$this->config['DB']['Connections']['Default']['host'].';dbname='.$this->config['DB']['Connections']['Default']['dbname'],
$this->config['DB']['Connections']['Default']['user'],
$this->config['DB']['Connections']['Default']['password']
);
}
/**
* Set cache
*
* @param $identifier
* @param $content
*/
public function set($identifier, $content)
{
// Read identifier
$query = $this->db->prepare("SELECT * FROM ".$this->tableName." WHERE identifier = :identifier");
$query->bindParam('identifier', $identifier, $this->db::PARAM_STR);
$query->execute();
if ($query->rowCount() == 0) {
// Make new entry
$query = $this->db->prepare("INSERT INTO ".$this->tableName." (crdate, identifier, content) VALUES (?, ?, ?)");
$query->execute([time(), $identifier, serialize($content)]);
} else {
// Update exiusting entry
$query = $this->db->prepare("UPDATE ".$this->tableName." SET crdate = :crdate, content = :content WHERE identifier = :identifier");
$content = serialize($content);
$time = time();
$query->bindParam('crdate', $time);
$query->bindParam('content', $content);
$query->bindParam('identifier', $identifier);
$query->execute();
}
}
/**
* Get cache
*
* @param $identifier
*
* @return false|mixed
*/
public function get($identifier)
{
// Read identifier
$query = $this->db->prepare("SELECT * FROM ".$this->tableName." WHERE identifier = :identifier");
$query->bindParam('identifier', $identifier, $this->db::PARAM_STR);
$query->execute();
// Return false ig nothing found
if ($query->rowCount() == 0) {
return false;
}
// Return cached data
return unserialize($query->fetch()['content']);
}
}
...@@ -4,19 +4,19 @@ ...@@ -4,19 +4,19 @@
## Version ## Version
4.0.2 4.0.3
## Dependencies ## Dependencies
* TYPO3 v10+ * TYPO3 v10+
* LU API v2.7+ * LU API v2.7+
* Calendarize v7+ * Calendarize v7+
## Author ## Author
Dainis Abols <dainis.abols@lu.lv> Dainis Abols <dainis.abols@lu.lv>
Lauris Karklis <lauris.karklis@lu.lv> Lauris Karklis <lauris.karklis@lu.lv>
## Template override constants ## Template override constants
``` ```
...@@ -24,7 +24,7 @@ Lauris Karklis <lauris.karklis@lu.lv> ...@@ -24,7 +24,7 @@ Lauris Karklis <lauris.karklis@lu.lv>
view.templateRootPath = EXT:lu_nabamusic/Resources/Private/Templates/ view.templateRootPath = EXT:lu_nabamusic/Resources/Private/Templates/
view.partialRootPath = EXT:lu_nabamusic/Resources/Private/Partials/ view.partialRootPath = EXT:lu_nabamusic/Resources/Private/Partials/
view.layoutRootPath = EXT:lu_nabamusic/Resources/Private/Layouts/ view.layoutRootPath = EXT:lu_nabamusic/Resources/Private/Layouts/
settings.cssFile = EXT:lu_nabamusic/Resources/Public/Css/styles.css settings.cssFile = EXT:lu_nabamusic/Resources/Public/Css/styles.css
settings.jsFile = EXT:lu_nabamusic/Resources/Public/JavaScript/scripts.js settings.jsFile = EXT:lu_nabamusic/Resources/Public/JavaScript/scripts.js
} }
...@@ -40,4 +40,3 @@ Lauris Karklis <lauris.karklis@lu.lv> ...@@ -40,4 +40,3 @@ Lauris Karklis <lauris.karklis@lu.lv>
| streamServer | Streaming server endpoint | | streamServer | Streaming server endpoint |
| top10StorageId | Top 10 storage page id | | top10StorageId | Top 10 storage page id |
| top25StorageId | Top 25 storage page id | | top25StorageId | Top 25 storage page id |
| cacheTime | Time in seconds to keep tops in cache |
{ {
"name": "luitd/lu-nabamusic", "name": "luitd/lu-nabamusic",
"version": "4.0.2", "version": "4.0.3",
"description": "Radio NABA plugin used for live stream, song tops and much more", "description": "Radio NABA plugin used for live stream, song tops and much more",
"type": "typo3-cms-extension", "type": "typo3-cms-extension",
"keywords": [ "keywords": [
"TYPO3", "TYPO3",
"extension" "extension"
], ],
"authors": [ "authors": [
{ {
"name": "Dainis Abols", "name": "Dainis Abols",
"email": "dainis@dainisabols.lv", "email": "dainis@dainisabols.lv",
"role": "Developer" "role": "Developer"
}, },
{ {
"name": "Lauris Karklis", "name": "Lauris Karklis",
"email": "lauris.karklis@lu.lv", "email": "lauris.karklis@lu.lv",
"role": "Developer" "role": "Developer"
} }
], ],
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"require": { "require": {
"typo3/cms-core": "^10", "typo3/cms-core": "^10",
"luitd/lu-api": "^2.7" "luitd/lu-api": "^2.7"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Lu\\LuNabamusic\\": "Classes" "Lu\\LuNabamusic\\": "Classes"
} }
}, },
"replace": { "replace": {
"typo3-ter/lu_nabamusic": "self.version" "typo3-ter/lu_nabamusic": "self.version"
}, },
"config": { "config": {
"vendor-dir": ".Build/vendor", "vendor-dir": ".Build/vendor",
"bin-dir": ".Build/bin" "bin-dir": ".Build/bin"
}, },
"scripts": { "scripts": {
"post-autoload-dump": [ "post-autoload-dump": [
"mkdir -p .Build/Web/typo3conf/ext/", "mkdir -p .Build/Web/typo3conf/ext/",
"[ -L .Build/Web/typo3conf/ext/lu_nabamusic ] || ln -snvf ../../../../. .Build/Web/typo3conf/ext/lu_nabamusic" "[ -L .Build/Web/typo3conf/ext/lu_nabamusic ] || ln -snvf ../../../../. .Build/Web/typo3conf/ext/lu_nabamusic"
] ]
}, },
"extra": { "extra": {
"typo3/cms": { "typo3/cms": {
"extension-key": "lu_nabamusic", "extension-key": "lu_nabamusic",
"cms-package-dir": "{$vendor-dir}/typo3/cms", "cms-package-dir": "{$vendor-dir}/typo3/cms",
"web-dir": ".Build/Web" "web-dir": ".Build/Web"
} }
} }
} }
...@@ -18,6 +18,3 @@ top10StorageId = ...@@ -18,6 +18,3 @@ top10StorageId =
# cat=Tops/set; type=string; label=Top 25 storage page id # cat=Tops/set; type=string; label=Top 25 storage page id
top25StorageId = top25StorageId =
# cat=Tops/set; type=string; label=Time in seconds to keep tops in cache
cacheTime =
...@@ -13,7 +13,7 @@ $EM_CONF[$_EXTKEY] = [ ...@@ -13,7 +13,7 @@ $EM_CONF[$_EXTKEY] = [
'modify_tables' => '', 'modify_tables' => '',
'clearCacheOnLoad' => 1, 'clearCacheOnLoad' => 1,
'lockType' => '', 'lockType' => '',
'version' => '4.0.2', 'version' => '4.0.3',
'constraints' => [ 'constraints' => [
'depends' => [ 'depends' => [
'typo3' => '10.0.0-10.9.99', 'typo3' => '10.0.0-10.9.99',
......
...@@ -23,10 +23,6 @@ call_user_func( ...@@ -23,10 +23,6 @@ call_user_func(
} }
); );
if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_naba_top'])) {
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_naba_top'] = [];
}
// Initialize task scheduler // Initialize task scheduler
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']['Lu\\LuNabamusic\\Tasks\\SongGatherTask'] = [ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks']['Lu\\LuNabamusic\\Tasks\\SongGatherTask'] = [
'extension' => 'tx_lunabamusic', 'extension' => 'tx_lunabamusic',
......
...@@ -72,6 +72,7 @@ CREATE TABLE tx_lunabamusic_domain_model_play ( ...@@ -72,6 +72,7 @@ CREATE TABLE tx_lunabamusic_domain_model_play (
uid INT(11) NOT NULL AUTO_INCREMENT, uid INT(11) NOT NULL AUTO_INCREMENT,
pid INT(11) DEFAULT 0 NOT NULL, pid INT(11) DEFAULT 0 NOT NULL,
time INT(11) DEFAULT 0 NOT NULL, time INT(11) DEFAULT 0 NOT NULL,
endtime INT(11) DEFAULT 0 NOT NULL,
artist VARCHAR(100) DEFAULT '' NOT NULL, artist VARCHAR(100) DEFAULT '' NOT NULL,
title VARCHAR(100) DEFAULT '' NOT NULL, title VARCHAR(100) DEFAULT '' NOT NULL,
prev INT(11) DEFAULT 0 NOT NULL, prev INT(11) DEFAULT 0 NOT NULL,
...@@ -85,3 +86,16 @@ CREATE TABLE tx_lunabamusic_domain_model_play ( ...@@ -85,3 +86,16 @@ CREATE TABLE tx_lunabamusic_domain_model_play (
KEY skantitle (title), KEY skantitle (title),
KEY artisttitle (artist) KEY artisttitle (artist)
); );
#
# Table structure for table 'tx_lunabamusic_cache'
#
CREATE TABLE tx_lunabamusic_cache
(
`id` INT(11) UNSIGNED DEFAULT 0 NOT NULL AUTO_INCREMENT,
`crdate` INT(11) DEFAULT 0 NOT NULL,
`identifier` VARCHAR(250) DEFAULT '' NOT NULL,
`content` LONGBLOB DEFAULT '' NOT NULL,
PRIMARY KEY (id)
);
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