735 lines
30 KiB
PHP
735 lines
30 KiB
PHP
<?php
|
|
/**
|
|
* Page Cache Ultimate, Page Cache standard and Speed pack are powered by Jpresta (jpresta . com)
|
|
*
|
|
* @author Jpresta
|
|
* @copyright Jpresta
|
|
* @license See the license of this module in file LICENSE.txt, thank you.
|
|
*/
|
|
|
|
use JPresta\SpeedPack\JprestaUtils;
|
|
|
|
if (!defined('_PS_VERSION_')) {exit;}
|
|
|
|
include_once(dirname(__FILE__) . '/../../pagecache.php');
|
|
|
|
class AdminPageCacheDatasController extends ModuleAdminController
|
|
{
|
|
public $php_self = null;
|
|
|
|
public function init()
|
|
{
|
|
if (!isset(Context::getContext()->link)) {
|
|
/* Link should be initialized in the context but sometimes it is not */
|
|
$https_link = (Tools::usingSecureMode() && Configuration::get('PS_SSL_ENABLED')) ? 'https://' : 'http://';
|
|
Context::getContext()->link = new Link($https_link, $https_link);
|
|
}
|
|
// avoid useless treatments
|
|
}
|
|
|
|
public function initHeader()
|
|
{
|
|
// avoid useless treatments
|
|
}
|
|
|
|
public function setMedia($isNewTheme = false)
|
|
{
|
|
// avoid useless treatments
|
|
}
|
|
|
|
public function initContent()
|
|
{
|
|
if (Tools::getIsset('url') && Tools::getIsset('id_context')) {
|
|
die(
|
|
Context::getContext()->smarty->fetch(_PS_MODULE_DIR_ . '/pagecache/views/templates/admin/get-content-tab-datas_cache.tpl')
|
|
. $this->module->getCache(Tools::getValue('id_shop'))->get(Tools::getValue('url'), PageCacheDAO::getContextKeyById(Tools::getValue('id_context')))
|
|
);
|
|
}
|
|
|
|
header('Access-Control-Allow-Origin: *');
|
|
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|
header('Cache-Control: max-age=300, private');
|
|
}
|
|
header('Content-type: application/json');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'GET' && Tools::getValue('type') === 'contexts') {
|
|
self::displayContextsDatas();
|
|
}
|
|
elseif ($_SERVER['REQUEST_METHOD'] === 'GET' && Tools::getValue('type') === 'ttfb') {
|
|
$this->displayTTFBDatas();
|
|
}
|
|
|
|
// DB table to use
|
|
$table = _DB_PREFIX_.PageCacheDAO::TABLE;
|
|
|
|
// Array of database columns which should be read and sent back to DataTables.
|
|
// The `db` parameter represents the column name in the database, while the `dt`
|
|
// parameter represents the DataTables column identifier. In this case simple
|
|
// indexes
|
|
$columns = array(
|
|
array('db' => 'url', 'dt' => 0, 'formatter' => function ($s, $row) {
|
|
return self::formatURL($s, $row);
|
|
}),
|
|
array('db' => 'cache_key', 'dt' => -1),
|
|
array('db' => 'id_shop', 'dt' => -1),
|
|
array('db' => 'id_context', 'dt' => 1, 'formatter' => function ($id_context) {
|
|
return self::formatContext(PageCacheDAO::getContextById((int)$id_context));
|
|
}),
|
|
array('db' => 'id_controller', 'dt' => 2, 'formatter' => function ($id_controller) {
|
|
return self::formatController($id_controller);
|
|
}),
|
|
array('db' => 'id_object', 'dt' => 3),
|
|
array('db' => 'last_gen', 'dt' => 4, 'formatter' => function ($d, $row) {
|
|
return self::formatLastGenerated($d, $row);
|
|
}),
|
|
array('db' => 'deleted', 'dt' => 5,'formatter' => function ($deleted) {
|
|
return self::formatDeleted($deleted);
|
|
}),
|
|
array('db' => 'count_hit', 'dt' => 6, 'formatter' => function ($s, $row) {
|
|
return self::formatHit($s, $row);
|
|
}),
|
|
array('db' => 'count_missed', 'dt' => -1),
|
|
);
|
|
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && Tools::getIsset('clear')) {
|
|
$searchUrl = trim($_POST['columns'][0]['search']['value']);
|
|
$searchContext = trim($_POST['columns'][1]['search']['value']);
|
|
$searchCtrl = (int) $_POST['columns'][2]['search']['value'];
|
|
$searchId = (int) $_POST['columns'][3]['search']['value'];
|
|
if ($searchCtrl || $searchId || $searchUrl || $searchContext) {
|
|
// Clear cache of filtered rows
|
|
self::simpleClear($_POST, $table, $columns);
|
|
}
|
|
else {
|
|
// Clear all
|
|
$this->module->clearCache('manually called from stats');
|
|
}
|
|
die(json_encode([]));
|
|
}
|
|
else {
|
|
$result = self::simple($_GET, $table, $columns);
|
|
die(json_encode($result));
|
|
}
|
|
}
|
|
|
|
private static function displayContextsDatas()
|
|
{
|
|
$data = [];
|
|
$pageSize = Tools::getValue('length', 10);
|
|
$start = Tools::getValue('start', 0);
|
|
$searchQuery = Tools::getValue('search', '');
|
|
$searchQuery = $searchQuery['value'];
|
|
if ($searchQuery && strpos($searchQuery, '=')!== false) {
|
|
$searchVals = explode(',', $searchQuery);
|
|
$whereClauses = [];
|
|
foreach ($searchVals as $searchVal) {
|
|
list($key, $val) = explode('=', $searchVal);
|
|
if ((int) $val > 0 && $key === 'id_lang') {
|
|
$whereClauses[] = 'id_lang=' . (int)$val;
|
|
} else if ((int) $val > 0 && $key === 'id_cur') {
|
|
$whereClauses[] = 'id_currency=' . (int)$val;
|
|
} else if ((int) $val > 0 && $key === 'id_country') {
|
|
$whereClauses[] = 'id_country=' . (int)$val;
|
|
} else if ($key === 'id_specs') {
|
|
if ((int) $val > 0) {
|
|
$whereClauses[] = 'id_specifics=' . (int)$val;
|
|
}
|
|
else if ($val === 'null') {
|
|
$whereClauses[] = 'id_specifics IS NULL';
|
|
}
|
|
} else if ((int) $val > 0 && $key === 'id_device') {
|
|
$whereClauses[] = 'id_device=' . (int)$val;
|
|
} else if ($key === 'id_group') {
|
|
if ((int) $val > 0) {
|
|
$whereClauses[] = 'id_fake_customer=' . (int)$val;
|
|
}
|
|
else if ($val === '0') {
|
|
$whereClauses[] = 'id_fake_customer IS NULL';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$select = 'SELECT *, count_hit_server + count_hit_static + count_hit_browser + count_hit_bfcache as count_hit,
|
|
count_hit_server + count_hit_static + count_hit_browser + count_hit_bfcache + count_missed as count_visit,
|
|
(count_hit_server + count_hit_static + count_hit_browser + count_hit_bfcache) * 100 / (count_hit_server + count_hit_static + count_hit_browser + count_hit_bfcache + count_missed) as hit_rate';
|
|
$selectTotal = 'SELECT count(*) as total_ctx, sum(count_hit_server + count_hit_static + count_hit_browser + count_hit_bfcache + count_missed) as total_visit_count, sum(count_bot) as total_bot_count';
|
|
$from = ' FROM `' . _DB_PREFIX_ . PageCacheDAO::TABLE_CONTEXTS . '`';
|
|
$whereClauses[] = 'id_shop=' . (int) Shop::getContextShopID();
|
|
$where = ' WHERE ' . implode(' AND ', $whereClauses);
|
|
$limit = " LIMIT $pageSize OFFSET $start";
|
|
|
|
$orders = Tools::getValue('order', []);
|
|
if (count($orders) === 1) {
|
|
$order = $orders[0];
|
|
$orderDir = $order['dir'];
|
|
switch ($order['column']) {
|
|
case 3:
|
|
$orderCol = 'hit_rate';
|
|
break;
|
|
case 4:
|
|
$orderCol = 'count_bot';
|
|
break;
|
|
case 2:
|
|
default:
|
|
$orderCol = 'count_visit';
|
|
break;
|
|
}
|
|
$orderBy = ' ORDER BY ' . $orderCol . ' ' . $orderDir;
|
|
}
|
|
else {
|
|
$orderBy = ' ORDER BY count_visit desc';
|
|
}
|
|
$total_ctx = 0;
|
|
$total_visit_count = 0;
|
|
$total_bot_count = 0;
|
|
$rows = JprestaUtils::dbSelectRows($select . $from . $where . $orderBy . $limit);
|
|
$rowsTotal = JprestaUtils::dbSelectRows($selectTotal . $from . $where);
|
|
if (count($rowsTotal) > 0) {
|
|
$total_ctx = (int) $rowsTotal[0]['total_ctx'];
|
|
$total_visit_count = (int) $rowsTotal[0]['total_visit_count'];
|
|
$total_bot_count = (int) $rowsTotal[0]['total_bot_count'];
|
|
}
|
|
if (count($rows) > 0) {
|
|
foreach ($rows as $row) {
|
|
$statsContext = PageCacheDAO::getStatsByContext($row['id']);
|
|
$data[] = (object) [
|
|
0 => $row['context_key'],
|
|
1 => self::formatContext($row),
|
|
2 => !$total_visit_count ? 0 : $row['count_visit'] . ' (' . round($row['count_visit'] * 100 / $total_visit_count, 2) . '%)',
|
|
3 => self::formatHit((int) $row['count_hit'], $row),
|
|
4 => !$total_bot_count ? 0 : $row['count_bot'] . ' (' . round($row['count_bot'] * 100 / $total_bot_count, 2) . '%)',
|
|
5 => !$statsContext['count'] ? '0/0 (0%)' : $statsContext['count_deleted'] . '/' . $statsContext['count'] . ' ('.round($statsContext['count_deleted'] * 100 / $statsContext['count'], 2).'%)'
|
|
];
|
|
}
|
|
}
|
|
$recordsTotal = $recordsFiltered = $total_ctx;
|
|
|
|
$datas = [
|
|
'data' => $data,
|
|
'recordsFiltered' => $recordsFiltered,
|
|
'recordsTotal' => $recordsTotal
|
|
];
|
|
die(json_encode($datas));
|
|
}
|
|
|
|
private function displayTTFBDatas()
|
|
{
|
|
$controller = Tools::getValue('controller_name');
|
|
$id_controller = PageCache::getManagedControllerId($controller);
|
|
$whereClause = 'WHERE id_shop=' . (int) Shop::getContextShopID();
|
|
if ($id_controller) {
|
|
$whereClause .= ' AND id_controller=' . (int) $id_controller;
|
|
}
|
|
$whereClause .= ' AND date_add >= CURRENT_DATE() - interval 13 DAY';
|
|
$query = 'SELECT UNIX_TIMESTAMP(day_add) AS day,
|
|
ROUND(AVG(ttfb_ms_hit_server)) AS ttfb_ms_hit_server,
|
|
ROUND(AVG(ttfb_ms_hit_static)) AS ttfb_ms_hit_static,
|
|
ROUND(AVG(ttfb_ms_hit_browser)) AS ttfb_ms_hit_browser,
|
|
ROUND(AVG(ttfb_ms_hit_bfcache)) AS ttfb_ms_hit_bfcache,
|
|
ROUND(AVG(ttfb_ms_missed)) AS ttfb_ms_missed
|
|
FROM `' . _DB_PREFIX_ . PageCacheDAO::TABLE_PERFS . '` '.$whereClause.' GROUP BY day_add ORDER BY day_add ASC;';
|
|
$rows = JprestaUtils::dbSelectRows($query);
|
|
$missed = $server = $static = $browser = $bf = [];
|
|
foreach ($rows as $row) {
|
|
$missed[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_missed']];
|
|
$server[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_hit_server']];
|
|
$static[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_hit_static']];
|
|
$browser[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_hit_browser']];
|
|
$bf[] = ['x' => (int)$row['day'], 'y' => $row['ttfb_ms_hit_bfcache']];
|
|
}
|
|
$datas = [
|
|
[
|
|
'values' => $missed,
|
|
'key' => $this->module->l('Cache not available'),
|
|
'color' => '#ce720b'
|
|
],
|
|
[
|
|
'values' => $server,
|
|
'key' => $this->module->l('Server cache'),
|
|
'color' => '#007e00'
|
|
],
|
|
[
|
|
'values' => $static,
|
|
'key' => $this->module->l('Static cache'),
|
|
'color' => '#00bd00'
|
|
],
|
|
[
|
|
'values' => $browser,
|
|
'key' => $this->module->l('Browser cache'),
|
|
'color' => '#00da00'
|
|
],
|
|
[
|
|
'values' => $bf,
|
|
'key' => $this->module->l('Back/forward cache'),
|
|
'color' => '#00ff00'
|
|
],
|
|
];
|
|
|
|
$query = 'SELECT date_format(MIN(day_add), \'%Y-%m-%d\') AS start_date,
|
|
SUM(1) AS total_count
|
|
FROM `' . _DB_PREFIX_ . PageCacheDAO::TABLE_PERFS . '` '.$whereClause;
|
|
$rows = JprestaUtils::dbSelectRows($query);
|
|
$start_date = 0;
|
|
$total_count = 0;
|
|
if (count($rows) > 0) {
|
|
$start_date = $rows[0]['start_date'];
|
|
$total_count = (int)$rows[0]['total_count'];
|
|
}
|
|
|
|
die(json_encode(['datas' => $datas, 'start_date' => $start_date, 'total_count' => $total_count]));
|
|
}
|
|
|
|
private static function formatController($id_controller) {
|
|
return PageCache::getManagedControllerNameById($id_controller);
|
|
}
|
|
|
|
private static function formatHit($count_hit, $row) {
|
|
$smarty = Context::getContext()->smarty;
|
|
$smarty->assign('count_hit', (int) $count_hit);
|
|
$smarty->assign('count_missed', (int) $row['count_missed']);
|
|
$smarty->assign('count_percent', round((((int) $count_hit * 100) / max(1, ((int) $count_hit + (int) $row['count_missed']))),1));
|
|
return $smarty->fetch(_PS_MODULE_DIR_ . '/pagecache/views/templates/admin/get-content-tab-datas_hit.tpl');
|
|
}
|
|
|
|
private static function formatDeleted($deleted) {
|
|
$smarty = Context::getContext()->smarty;
|
|
$smarty->assign('deleted', $deleted);
|
|
$smarty->assign('isPs17', Tools::version_compare(_PS_VERSION_, '1.6', '>'));
|
|
return $smarty->fetch(_PS_MODULE_DIR_ . '/pagecache/views/templates/admin/get-content-tab-datas_deleted.tpl');
|
|
}
|
|
|
|
private static function formatLastGenerated($d, $row) {
|
|
$lastGen = strtotime($d);
|
|
$cache_ttl = 60 * ((int)Configuration::get('pagecache_'.PageCache::getManagedControllerNameById($row['id_controller']).'_timeout'));
|
|
$age = time() - $lastGen;
|
|
$ttl = $cache_ttl - $age;
|
|
if ($cache_ttl <= 0) {
|
|
$percent = 0;
|
|
}
|
|
elseif ($cache_ttl <= $age) {
|
|
$percent = 100;
|
|
}
|
|
else {
|
|
$percent = $age * 100 / $cache_ttl;
|
|
}
|
|
$color = '#ccc';
|
|
if ($percent >= 100) {
|
|
$color = 'red';
|
|
}
|
|
else if ($percent >= 95) {
|
|
$color = 'orange';
|
|
}
|
|
|
|
$smarty = Context::getContext()->smarty;
|
|
$smarty->assign('lastGen', strtotime($d));
|
|
if ($cache_ttl == -60) {
|
|
$ttl_msg = 'forever';
|
|
}
|
|
elseif ($ttl <= 0) {
|
|
$ttl_msg = 'dead';
|
|
}
|
|
else {
|
|
$ttl_msg = self::getNiceDuration($ttl);
|
|
}
|
|
$smarty->assign('age', self::getNiceDuration($age));
|
|
$smarty->assign('last_gen', date('Y-m-d H:i:s', strtotime($d)));
|
|
$smarty->assign('ttl_msg', $ttl_msg);
|
|
$smarty->assign('color', $color);
|
|
$smarty->assign('percent', $percent);
|
|
return $smarty->fetch(_PS_MODULE_DIR_ . '/pagecache/views/templates/admin/get-content-tab-datas_lastgen.tpl');
|
|
}
|
|
|
|
private static function formatURL($url, $row) {
|
|
|
|
$smarty = Context::getContext()->smarty;
|
|
$smarty->clearAssign('flag_lang');
|
|
$smarty->clearAssign('flag_currency');
|
|
$smarty->clearAssign('flag_country');
|
|
$smarty->clearAssign('flag_device');
|
|
$smarty->clearAssign('flag_group');
|
|
$smarty->clearAssign('flag_tax_manager');
|
|
$smarty->clearAssign('flag_specifics');
|
|
$smarty->clearAssign('flag_specifics_more');
|
|
$smarty->clearAssign('flag_v_css');
|
|
$smarty->clearAssign('flag_v_js');
|
|
$smarty->clearAssign('url_cached');
|
|
|
|
if (!empty($row['id_lang'])) {
|
|
$smarty->assign('flag_lang', $row['id_lang']);
|
|
}
|
|
if (!empty($row['id_currency'])) {
|
|
$currency = new Currency($row['id_currency']);
|
|
$smarty->assign('flag_currency', $currency->sign);
|
|
}
|
|
if (!empty($row['id_country'])) {
|
|
$country = new Country($row['id_country']);
|
|
$smarty->assign('flag_country', $country->iso_code);
|
|
}
|
|
if (!empty($row['id_device'])) {
|
|
if ($row['id_device'] == PageCache::DEVICE_COMPUTER) {
|
|
$smarty->assign('flag_device', 'desktop');
|
|
}
|
|
elseif ($row['id_device'] == PageCache::DEVICE_TABLET) {
|
|
$smarty->assign('flag_device', 'tablet');
|
|
}
|
|
elseif ($row['id_device'] == PageCache::DEVICE_MOBILE) {
|
|
$smarty->assign('flag_device', 'mobile');
|
|
}
|
|
}
|
|
if (!empty($row['id_fake_customer'])) {
|
|
$jCustomer = new JprestaCustomer((int)$row['id_fake_customer']);
|
|
$smarty->assign('flag_group', $jCustomer->getLabel() . ' (#'.$row['id_fake_customer'].')');
|
|
}
|
|
if (!empty($row['id_tax_csz'])) {
|
|
$tax_manager_json = PageCacheDAO::getDetailsById($row['id_tax_csz']);
|
|
$smarty->assign('flag_tax_manager', $row['id_tax_csz']);
|
|
$smarty->assign('flag_tax_manager_more', JprestaUtilsTaxManager::toPrettyString($tax_manager_json));
|
|
}
|
|
if (!empty($row['id_specifics'])) {
|
|
$specifics = PageCacheDAO::getDetailsById($row['id_specifics']);
|
|
$jscks = new JprestaCacheKeySpecifics($specifics);
|
|
$smarty->assign('flag_specifics', $row['id_specifics']);
|
|
$smarty->assign('flag_specifics_more', $jscks->toPrettyString());
|
|
}
|
|
if (!empty($row['v_css'])) {
|
|
$smarty->assign('flag_v_css', $row['v_css']);
|
|
}
|
|
if (!empty($row['v_js'])) {
|
|
$smarty->assign('flag_v_js', $row['v_js']);
|
|
}
|
|
|
|
$smarty->assign('url', $url);
|
|
|
|
if (array_key_exists('deleted', $row) && !$row['deleted'] && $row['cache_key']) {
|
|
$cacheLink =
|
|
Context::getContext()->link->getAdminLink(
|
|
'AdminPageCacheDatas',
|
|
true,
|
|
array(),
|
|
array('url' => $url, 'id_context' => $row['id_context']));
|
|
if (Tools::version_compare(_PS_VERSION_, '1.7', '<')) {
|
|
$cacheLink .= '&url=' . urlencode($url) . '&id_context=' . (int) $row['id_context'];
|
|
}
|
|
$smarty->assign('url_cached', $cacheLink);
|
|
}
|
|
|
|
$smarty->assign('isPs17', Tools::version_compare(_PS_VERSION_, '1.6', '>'));
|
|
return $smarty->fetch(_PS_MODULE_DIR_ . '/pagecache/views/templates/admin/get-content-tab-datas_url.tpl');
|
|
|
|
}
|
|
|
|
public static function formatContext($contextRow) {
|
|
|
|
$smarty = Context::getContext()->smarty;
|
|
$smarty->clearAssign('flag_lang');
|
|
$smarty->clearAssign('flag_currency');
|
|
$smarty->clearAssign('flag_country');
|
|
$smarty->clearAssign('flag_device');
|
|
$smarty->clearAssign('flag_group');
|
|
$smarty->clearAssign('flag_tax_manager');
|
|
$smarty->clearAssign('flag_specifics');
|
|
$smarty->clearAssign('flag_specifics_more');
|
|
$smarty->clearAssign('flag_v_css');
|
|
$smarty->clearAssign('flag_v_js');
|
|
|
|
$smarty->assign('id_context', $contextRow['id']);
|
|
if (!empty($contextRow['id_lang'])) {
|
|
$smarty->assign('flag_lang', $contextRow['id_lang']);
|
|
}
|
|
if (!empty($contextRow['id_currency'])) {
|
|
$currency = new Currency($contextRow['id_currency']);
|
|
$smarty->assign('flag_currency', $currency->sign);
|
|
}
|
|
if (!empty($contextRow['id_country'])) {
|
|
$country = new Country($contextRow['id_country']);
|
|
$smarty->assign('flag_country', $country->iso_code);
|
|
}
|
|
if (!empty($contextRow['id_device'])) {
|
|
if ($contextRow['id_device'] == PageCache::DEVICE_COMPUTER) {
|
|
$smarty->assign('flag_device', 'desktop');
|
|
}
|
|
elseif ($contextRow['id_device'] == PageCache::DEVICE_TABLET) {
|
|
$smarty->assign('flag_device', 'tablet');
|
|
}
|
|
elseif ($contextRow['id_device'] == PageCache::DEVICE_MOBILE) {
|
|
$smarty->assign('flag_device', 'mobile');
|
|
}
|
|
}
|
|
if (!empty($contextRow['id_fake_customer'])) {
|
|
$jCustomer = new JprestaCustomer((int)$contextRow['id_fake_customer']);
|
|
$smarty->assign('flag_group', $jCustomer->getLabel() . ' (#'.$contextRow['id_fake_customer'].')');
|
|
}
|
|
if (!empty($contextRow['id_tax_csz'])) {
|
|
$tax_manager_json = PageCacheDAO::getDetailsById($contextRow['id_tax_csz']);
|
|
$smarty->assign('flag_tax_manager', $contextRow['id_tax_csz']);
|
|
$smarty->assign('flag_tax_manager_more', JprestaUtilsTaxManager::toPrettyString($tax_manager_json));
|
|
}
|
|
if (!empty($contextRow['id_specifics'])) {
|
|
$specifics = PageCacheDAO::getDetailsById($contextRow['id_specifics']);
|
|
$jscks = new JprestaCacheKeySpecifics($specifics);
|
|
$smarty->assign('flag_specifics', $contextRow['id_specifics']);
|
|
$smarty->assign('flag_specifics_more', $jscks->toPrettyString());
|
|
}
|
|
if (!empty($contextRow['v_css'])) {
|
|
$smarty->assign('flag_v_css', $contextRow['v_css']);
|
|
}
|
|
if (!empty($contextRow['v_js'])) {
|
|
$smarty->assign('flag_v_js', $contextRow['v_js']);
|
|
}
|
|
|
|
$smarty->assign('isPs17', Tools::version_compare(_PS_VERSION_, '1.6', '>'));
|
|
return $smarty->fetch(_PS_MODULE_DIR_ . '/pagecache/views/templates/admin/get-content-tab-datas_context.tpl');
|
|
|
|
}
|
|
|
|
private static function getNiceDuration($durationInSeconds) {
|
|
$duration = '';
|
|
if ($durationInSeconds < 0) {
|
|
$duration = '-';
|
|
}
|
|
else {
|
|
$days = floor($durationInSeconds / 86400);
|
|
$durationInSeconds -= $days * 86400;
|
|
$hours = floor($durationInSeconds / 3600);
|
|
$durationInSeconds -= $hours * 3600;
|
|
$minutes = floor($durationInSeconds / 60);
|
|
$seconds = $durationInSeconds - $minutes * 60;
|
|
|
|
if ($days > 0) {
|
|
$duration .= $days . ' days';
|
|
}
|
|
if ($hours > 0) {
|
|
$duration .= ' ' . $hours . ' hours';
|
|
}
|
|
if ($minutes > 0) {
|
|
$duration .= ' ' . $minutes . ' minutes';
|
|
}
|
|
if ($seconds > 0) {
|
|
$duration .= ' ' . $seconds . ' seconds';
|
|
}
|
|
}
|
|
return $duration;
|
|
}
|
|
|
|
/**
|
|
* Create the data output array for the DataTables rows
|
|
*
|
|
* @param array $columns Column information array
|
|
* @param array $data Data from the SQL get
|
|
* @return array Formatted data in a row based format
|
|
*/
|
|
private static function data_output($columns, $data)
|
|
{
|
|
$out = array();
|
|
for ($i = 0, $ien = count($data); $i < $ien; $i++) {
|
|
$row = array();
|
|
for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
|
|
$column = $columns[$j];
|
|
// Is there a formatter?
|
|
if (isset($column['formatter'])) {
|
|
$row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
|
|
} else {
|
|
$row[$column['dt']] = $data[$i][$columns[$j]['db']];
|
|
}
|
|
}
|
|
$out[] = $row;
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* Paging
|
|
*
|
|
* Construct the LIMIT clause for server-side processing SQL query
|
|
*
|
|
* @param array $request Data sent to server by DataTables
|
|
* @return string SQL limit clause
|
|
*/
|
|
private static function limit($request)
|
|
{
|
|
$limit = '';
|
|
if (isset($request['start']) && $request['length'] != -1) {
|
|
$limit = "LIMIT " . ((int)$request['start']) . ", " . ((int)$request['length']);
|
|
}
|
|
return $limit;
|
|
}
|
|
|
|
/**
|
|
* Ordering
|
|
*
|
|
* Construct the ORDER BY clause for server-side processing SQL query
|
|
*
|
|
* @param array $request Data sent to server by DataTables
|
|
* @param array $columns Column information array
|
|
* @return string SQL order by clause
|
|
*/
|
|
private static function order($request, $columns)
|
|
{
|
|
$order = '';
|
|
if (isset($request['order']) && count($request['order'])) {
|
|
$orderBy = array();
|
|
$dtColumns = self::pluck($columns, 'dt');
|
|
for ($i = 0, $ien = count($request['order']); $i < $ien; $i++) {
|
|
// Convert the column index into the column data property
|
|
$columnIdx = (int)($request['order'][$i]['column']);
|
|
$requestColumn = $request['columns'][$columnIdx];
|
|
$columnIdx = array_search($requestColumn['data'], $dtColumns);
|
|
$column = $columns[$columnIdx];
|
|
if ($requestColumn['orderable'] == 'true') {
|
|
$dir = $request['order'][$i]['dir'] === 'asc' ?
|
|
'ASC' :
|
|
'DESC';
|
|
if ($column['db']=='count_hit') {
|
|
// Special case
|
|
$orderBy[] = 'count_hit+count_missed ' . $dir;
|
|
}
|
|
else {
|
|
$orderBy[] = '`' . $column['db'] . '` ' . $dir;
|
|
}
|
|
}
|
|
}
|
|
if (count($orderBy)) {
|
|
$order = 'ORDER BY ' . implode(', ', $orderBy);
|
|
}
|
|
}
|
|
return $order;
|
|
}
|
|
|
|
/**
|
|
* Searching / Filtering
|
|
*
|
|
* Construct the WHERE clause for server-side processing SQL query.
|
|
*
|
|
* NOTE this does not match the built-in DataTables filtering which does it
|
|
* word by word on any field. It's possible to do here performance on large
|
|
* databases would be very poor
|
|
*
|
|
* @param array $request Data sent to server by DataTables
|
|
* @param array $columns Column information array
|
|
* @return string SQL where clause
|
|
*/
|
|
private static function filter ( $request, $columns )
|
|
{
|
|
$columnSearch = array();
|
|
$dtColumns = self::pluck( $columns, 'dt' );
|
|
|
|
// Individual column filtering
|
|
if ( isset( $request['columns'] ) ) {
|
|
for ( $i=0, $ien=count($request['columns']) ; $i<$ien ; $i++ ) {
|
|
$requestColumn = $request['columns'][$i];
|
|
$columnIdx = array_search( $requestColumn['data'], $dtColumns );
|
|
$column = $columns[ $columnIdx ];
|
|
|
|
$str = $requestColumn['search']['value'];
|
|
|
|
if ( $requestColumn['searchable'] == 'true' && $str != '' ) {
|
|
if(!empty($column['db'])){
|
|
if ($column['db'] === 'url') {
|
|
$columnSearch[] = "`" . $column['db'] . "` LIKE '%" . $str . "%'";
|
|
}
|
|
else {
|
|
$columnSearch[] = "`" . $column['db'] . "` = '" . $str . "'";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Combine the filters into a single string
|
|
$where = 'id_shop IN (' . implode(',', Shop::getContextListShopID()) . ')';
|
|
|
|
if ( count( $columnSearch ) ) {
|
|
$where = $where === '' ?
|
|
implode(' AND ', $columnSearch) :
|
|
$where .' AND '. implode(' AND ', $columnSearch);
|
|
}
|
|
|
|
if ( $where !== '' ) {
|
|
$where = 'WHERE '.$where;
|
|
}
|
|
|
|
return $where;
|
|
}
|
|
|
|
/**
|
|
* Perform the SQL queries needed for an server-side processing requested,
|
|
* utilising the helper functions of this class, limit(), order() and
|
|
* filter() among others. The returned array is ready to be encoded as JSON
|
|
* in response to an SSP request, or can be modified if needed before
|
|
* sending back to the client.
|
|
*
|
|
* @param array $request Data sent to server by DataTables
|
|
* @param string $table SQL table to query
|
|
* @param array $columns Column information array
|
|
* @return array Server-side processing response array
|
|
*/
|
|
private static function simple($request, $table, $columns)
|
|
{
|
|
// Build the SQL query string from the request
|
|
$limit = self::limit($request);
|
|
$order = self::order($request, $columns);
|
|
$where = self::filter( $request, $columns);
|
|
|
|
// Main query to actually get the data
|
|
try {
|
|
$data = JprestaUtils::dbSelectRows("SELECT `" . implode("`, `", self::pluck($columns, 'db')) . "`
|
|
FROM `$table`
|
|
$where
|
|
$order
|
|
$limit"
|
|
);
|
|
// Data set length after filtering
|
|
// Total data set length
|
|
$recordsFiltered = $recordsTotal = JprestaUtils::dbGetValue("SELECT COUNT(*) FROM `$table` $where");
|
|
} catch (Exception $e) {
|
|
die($e->getMessage());
|
|
}
|
|
/*
|
|
* Output
|
|
*/
|
|
return array(
|
|
"draw" => isset ($request['draw']) ? (int)$request['draw'] : 0,
|
|
"recordsTotal" => (int)$recordsTotal,
|
|
"recordsFiltered" => (int)$recordsFiltered,
|
|
"data" => self::data_output($columns, $data)
|
|
);
|
|
}
|
|
|
|
private static function simpleClear($request, $table, $columns)
|
|
{
|
|
// Build the SQL query string from the request
|
|
$where = self::filter($request, $columns);
|
|
|
|
// Main query to actually get the data
|
|
try {
|
|
$rows = JprestaUtils::dbSelectRows("SELECT * FROM `$table` as c $where AND deleted=0 LIMIT 1000");
|
|
PageCacheDAO::deleteCachedPages($rows, false);
|
|
} catch (Exception $e) {
|
|
die($e->getMessage());
|
|
}
|
|
}
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Internal methods
|
|
*/
|
|
|
|
/**
|
|
* Pull a particular property from each assoc. array in a numeric array,
|
|
* returning and array of the property values from each item.
|
|
*
|
|
* @param array $a Array to get data from
|
|
* @param string $prop Property to read
|
|
* @return array Array of property values
|
|
*/
|
|
private static function pluck($a, $prop)
|
|
{
|
|
$out = array();
|
|
for ($i = 0, $len = count($a); $i < $len; $i++) {
|
|
$out[] = $a[$i][$prop];
|
|
}
|
|
return $out;
|
|
}
|
|
}
|