1c25e802bSgerardnico<?php 2c25e802bSgerardnico 32c067407Sgerardnicouse ComboStrap\Analytics; 4db974367Sgerardnicouse Combostrap\AnalyticsMenuItem; 5db974367Sgerardnicouse ComboStrap\Auth; 655d4462bSgerardnicouse ComboStrap\LogUtility; 7c25e802bSgerardnicouse ComboStrap\Page; 855d4462bSgerardnicouse ComboStrap\Sqlite; 9c25e802bSgerardnico 10c25e802bSgerardnico/** 11c25e802bSgerardnico * Copyright (c) 2021. ComboStrap, Inc. and its affiliates. All Rights Reserved. 12c25e802bSgerardnico * 13c25e802bSgerardnico * This source code is licensed under the GPL license found in the 14c25e802bSgerardnico * COPYING file in the root directory of this source tree. 15c25e802bSgerardnico * 16c25e802bSgerardnico * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 17c25e802bSgerardnico * @author ComboStrap <support@combostrap.com> 18c25e802bSgerardnico * 19c25e802bSgerardnico */ 20c25e802bSgerardnico 212c067407Sgerardnicorequire_once(__DIR__ . '/../class/' . 'Analytics.php'); 22db974367Sgerardnicorequire_once(__DIR__ . '/../class/' . 'Auth.php'); 23db974367Sgerardnicorequire_once(__DIR__ . '/../class/' . 'AnalyticsMenuItem.php'); 242c067407Sgerardnico 25c25e802bSgerardnico/** 26c25e802bSgerardnico * Class action_plugin_combo_analytics 27c25e802bSgerardnico * Update the analytics data 28c25e802bSgerardnico */ 29c25e802bSgerardnicoclass action_plugin_combo_analytics extends DokuWiki_Action_Plugin 30c25e802bSgerardnico{ 31c25e802bSgerardnico 32c25e802bSgerardnico 33c25e802bSgerardnico public function register(Doku_Event_Handler $controller) 34c25e802bSgerardnico { 352c067407Sgerardnico 36c25e802bSgerardnico /** 37c42a1196Sgerardnico * Analytics to refresh because they have lost or gain a backlinks 38c42a1196Sgerardnico * are done via Sqlite table (The INDEXER_TASKS_RUN gives a way to 39c42a1196Sgerardnico * manipulate this queue) 40266b617eSgerardnico * 41266b617eSgerardnico * There is no need to do it at page write 42266b617eSgerardnico * https://www.dokuwiki.org/devel:event:io_wikipage_write 43266b617eSgerardnico * because after the page is written, the page is shown and trigger the index tasks run 44d262537cSgerardnico * 45d262537cSgerardnico * We do it after because if there is an error 46d262537cSgerardnico * We will not stop the Dokuwiki Processing 47c42a1196Sgerardnico */ 48d262537cSgerardnico $controller->register_hook('INDEXER_TASKS_RUN', 'AFTER', $this, 'handle_refresh_analytics', array()); 4955d4462bSgerardnico 50db974367Sgerardnico /** 51db974367Sgerardnico * Add a icon in the page tools menu 52db974367Sgerardnico * https://www.dokuwiki.org/devel:event:menu_items_assembly 53db974367Sgerardnico */ 54db974367Sgerardnico $controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'handle_page_tools'); 55db974367Sgerardnico 56c25e802bSgerardnico } 57c25e802bSgerardnico 5855d4462bSgerardnico public function handle_refresh_analytics(Doku_Event $event, $param) 5955d4462bSgerardnico { 6055d4462bSgerardnico 61c42a1196Sgerardnico /** 62c42a1196Sgerardnico * Check that the actual page has analytics data 63c42a1196Sgerardnico * (if there is a cache, it's pretty quick) 64c42a1196Sgerardnico */ 65c42a1196Sgerardnico global $ID; 66*d81822adSgerardnico $page = new Page($ID); 67*d81822adSgerardnico if ($page->shouldAnalyticsProcessOccurs()) { 687c33ecc6Sgerardnico $page->processAnalytics(); 6955d4462bSgerardnico } 7055d4462bSgerardnico 71*d81822adSgerardnico /** 72*d81822adSgerardnico * Process the analytics to refresh 73*d81822adSgerardnico */ 74*d81822adSgerardnico $this->analyticsBatchBackgroundRefresh(); 75*d81822adSgerardnico 7655d4462bSgerardnico } 77db974367Sgerardnico 78*d81822adSgerardnico public function handle_page_tools(Doku_Event $event, $param) 79*d81822adSgerardnico { 80db974367Sgerardnico 81d262537cSgerardnico if (!Auth::isWriter()) { 82db974367Sgerardnico return; 83db974367Sgerardnico } 84db974367Sgerardnico 85db974367Sgerardnico /** 86db974367Sgerardnico * The `view` property defines the menu that is currently built 87db974367Sgerardnico * https://www.dokuwiki.org/devel:menus 88db974367Sgerardnico * If this is not the page menu, return 89db974367Sgerardnico */ 90db974367Sgerardnico if ($event->data['view'] != 'page') return; 91db974367Sgerardnico 92db974367Sgerardnico global $INFO; 93db974367Sgerardnico if (!$INFO['exists']) { 94db974367Sgerardnico return; 95db974367Sgerardnico } 96db974367Sgerardnico array_splice($event->data['items'], -1, 0, array(new AnalyticsMenuItem())); 97db974367Sgerardnico 98db974367Sgerardnico } 99*d81822adSgerardnico 100*d81822adSgerardnico private function analyticsBatchBackgroundRefresh() 101*d81822adSgerardnico { 102*d81822adSgerardnico $sqlite = Sqlite::getSqlite(); 103*d81822adSgerardnico $res = $sqlite->query("SELECT ID FROM ANALYTICS_TO_REFRESH"); 104*d81822adSgerardnico if (!$res) { 105*d81822adSgerardnico LogUtility::msg("There was a problem during the select: {$sqlite->getAdapter()->getDb()->errorInfo()}"); 106*d81822adSgerardnico } 107*d81822adSgerardnico $rows = $sqlite->res2arr($res, true); 108*d81822adSgerardnico $sqlite->res_close($res); 109*d81822adSgerardnico 110*d81822adSgerardnico /** 111*d81822adSgerardnico * In case of a start or if there is a recursive bug 112*d81822adSgerardnico * We don't want to take all the resources 113*d81822adSgerardnico */ 114*d81822adSgerardnico $maxRefresh = 5; 115*d81822adSgerardnico $maxRefreshLow = 2; 116*d81822adSgerardnico if (sizeof($rows) > $maxRefresh) { 117*d81822adSgerardnico LogUtility::msg("There is more than {$maxRefresh} page to refresh in the queue (table `ANALYTICS_TO_REFRESH`). Batch background Analytics refresh was reduced to {$maxRefreshLow} page to not hit the computer resources.", LogUtility::LVL_MSG_ERROR, "analytics"); 118*d81822adSgerardnico $maxRefresh = $maxRefreshLow; 119*d81822adSgerardnico } 120*d81822adSgerardnico $refreshCounter = 0; 121*d81822adSgerardnico foreach ($rows as $row) { 122*d81822adSgerardnico $page = new Page($row['ID']); 123*d81822adSgerardnico $page->processAnalytics(); 124*d81822adSgerardnico $refreshCounter++; 125*d81822adSgerardnico if ($refreshCounter>=$maxRefresh){ 126*d81822adSgerardnico break; 127*d81822adSgerardnico } 128*d81822adSgerardnico } 129*d81822adSgerardnico 130*d81822adSgerardnico } 131c25e802bSgerardnico} 132c25e802bSgerardnico 133c25e802bSgerardnico 134c25e802bSgerardnico 135