From 9076064890c4b3705debe409cbf7c0542b23dc3f Mon Sep 17 00:00:00 2001 From: Thomas Steur <tsteur@users.noreply.github.com> Date: Thu, 5 Oct 2017 09:09:08 +1300 Subject: [PATCH] Fix reports are not cached per site (#12148) Because of the Reports.addReport and Reports.filterReports events, reports may be different per website. However, currently, we cache only plugin aware. For now I try to detect idSite based on that parameter --- core/Plugin/ReportsProvider.php | 48 ++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/core/Plugin/ReportsProvider.php b/core/Plugin/ReportsProvider.php index f134009881..c1ceb3c377 100644 --- a/core/Plugin/ReportsProvider.php +++ b/core/Plugin/ReportsProvider.php @@ -8,11 +8,14 @@ */ namespace Piwik\Plugin; +use Piwik\Cache; use Piwik\CacheId; use Piwik\Category\CategoryList; +use Piwik\Common; use Piwik\Piwik; use Piwik\Plugin; use Piwik\Cache as PiwikCache; +use Piwik\Site; /** * Get reports that are defined by plugins. @@ -44,11 +47,44 @@ class ReportsProvider private static function getMapOfModuleActionsToReport() { - $cacheId = CacheId::pluginAware('ReportFactoryMap'); + $cacheKey = 'ReportFactoryMap'; + $idSite = Common::getRequestVar('idSite', 0, 'int'); - $cache = PiwikCache::getEagerCache(); - if ($cache->contains($cacheId)) { - $mapApiToReport = $cache->fetch($cacheId); + if (!empty($idSite)) { + // some reports may be per site! + $cacheKey .= '_' . (int) $idSite; + } + + // fallback eg fror API.getReportMetadata and API.getSegmentsMetadata + $idSites = Common::getRequestVar('idSites', '', $type = null); + if (!empty($idSites)) { + + $transientCache = Cache::getTransientCache(); + $transientCacheKey = 'ReportIdSitesParam'; + if ($transientCache->contains($transientCacheKey)) { + $idSites = $transientCache->fetch($transientCacheKey); + } else { + // this may be called 100 times during one page request and may go to DB, therefore have to cache + $idSites = Site::getIdSitesFromIdSitesString($idSites); + sort($idSites);// we sort to reuse the cache key as often as possible + $transientCache->save($transientCacheKey, $idSites); + } + + // it is important to not use either idsite, or idsites in the cache key but to include both for security reasons + // otherwise someone may specify idSite=5&idSites=7 and if then a plugin is eg only looking at idSites param + // we could return a wrong result (eg API.getSegmentsMetadata) + if (count($idSites) <= 5) { + $cacheKey .= '_' . implode('_', $idSites); // we keep the cache key readable when possible + } else { + $cacheKey .= '_' . md5(implode('_', $idSites)); // we need to shorten it + } + } + + $lazyCacheId = CacheId::pluginAware($cacheKey); + + $cache = PiwikCache::getLazyCache(); + if ($cache->contains($lazyCacheId)) { + $mapApiToReport = $cache->fetch($lazyCacheId); } else { $reports = new static(); $reports = $reports->getAllReports(); @@ -66,7 +102,7 @@ class ReportsProvider $mapApiToReport[$key] = get_class($report); } - $cache->save($cacheId, $mapApiToReport); + $cache->save($lazyCacheId, $mapApiToReport); } return $mapApiToReport; @@ -222,4 +258,4 @@ class ReportsProvider { return Plugin\Manager::getInstance()->findMultipleComponents('Reports', '\\Piwik\\Plugin\\Report'); } -} \ No newline at end of file +} -- GitLab