PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.0.3
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.0.3
5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Plugin / ReportsProvider.php
matomo / app / core / Plugin Last commit date
ConsoleCommand 2 years ago Dimension 2 years ago API.php 2 years ago AggregatedMetric.php 2 years ago ArchivedMetric.php 2 years ago Archiver.php 2 years ago Categories.php 2 years ago ComponentFactory.php 2 years ago ComputedMetric.php 2 years ago ConsoleCommand.php 2 years ago Controller.php 2 years ago ControllerAdmin.php 2 years ago Dependency.php 2 years ago LogTablesProvider.php 2 years ago Manager.php 2 years ago Menu.php 2 years ago MetadataLoader.php 2 years ago Metric.php 2 years ago PluginException.php 2 years ago ProcessedMetric.php 2 years ago ReleaseChannels.php 2 years ago Report.php 2 years ago ReportsProvider.php 2 years ago RequestProcessors.php 2 years ago Segment.php 2 years ago SettingsProvider.php 2 years ago Tasks.php 2 years ago ThemeStyles.php 2 years ago ViewDataTable.php 2 years ago Visualization.php 2 years ago WidgetsProvider.php 2 years ago
ReportsProvider.php
248 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 *
9 */
10 namespace Piwik\Plugin;
11
12 use Piwik\Cache;
13 use Piwik\CacheId;
14 use Piwik\Category\CategoryList;
15 use Piwik\Common;
16 use Piwik\Piwik;
17 use Piwik\Plugin;
18 use Piwik\Cache as PiwikCache;
19 use Piwik\Site;
20 /**
21 * Get reports that are defined by plugins.
22 */
23 class ReportsProvider
24 {
25 private $categoryList;
26 /**
27 * Get an instance of a specific report belonging to the given module and having the given action.
28 * @param string $module
29 * @param string $action
30 * @return null|\Piwik\Plugin\Report
31 * @api
32 */
33 public static function factory($module, $action)
34 {
35 $listApiToReport = self::getMapOfModuleActionsToReport();
36 $api = $module . '.' . ucfirst($action);
37 if (!array_key_exists($api, $listApiToReport)) {
38 return null;
39 }
40 $klassName = $listApiToReport[$api];
41 return new $klassName();
42 }
43 private static function getMapOfModuleActionsToReport()
44 {
45 $cacheKey = 'ReportFactoryMap';
46 $idSite = Common::getRequestVar('idSite', 0, 'int');
47 if (!empty($idSite)) {
48 // some reports may be per site!
49 $cacheKey .= '_' . (int) $idSite;
50 }
51 // fallback eg fror API.getReportMetadata and API.getSegmentsMetadata
52 $idSites = Common::getRequestVar('idSites', '', $type = null);
53 if (!empty($idSites)) {
54 $transientCache = Cache::getTransientCache();
55 $transientCacheKey = 'ReportIdSitesParam';
56 if ($transientCache->contains($transientCacheKey)) {
57 $idSites = $transientCache->fetch($transientCacheKey);
58 } else {
59 // this may be called 100 times during one page request and may go to DB, therefore have to cache
60 $idSites = Site::getIdSitesFromIdSitesString($idSites);
61 sort($idSites);
62 // we sort to reuse the cache key as often as possible
63 $transientCache->save($transientCacheKey, $idSites);
64 }
65 // it is important to not use either idsite, or idsites in the cache key but to include both for security reasons
66 // otherwise someone may specify idSite=5&idSites=7 and if then a plugin is eg only looking at idSites param
67 // we could return a wrong result (eg API.getSegmentsMetadata)
68 if (count($idSites) <= 5) {
69 $cacheKey .= '_' . implode('_', $idSites);
70 // we keep the cache key readable when possible
71 } else {
72 $cacheKey .= '_' . md5(implode('_', $idSites));
73 // we need to shorten it
74 }
75 }
76 $lazyCacheId = CacheId::pluginAware($cacheKey);
77 $cache = PiwikCache::getLazyCache();
78 $mapApiToReport = $cache->fetch($lazyCacheId);
79 if (empty($mapApiToReport)) {
80 $reports = new static();
81 $reports = $reports->getAllReports();
82 $mapApiToReport = array();
83 foreach ($reports as $report) {
84 $key = $report->getModule() . '.' . ucfirst($report->getAction());
85 if (isset($mapApiToReport[$key]) && $report->getParameters()) {
86 // sometimes there are multiple reports with same module/action but different parameters.
87 // we might pick the "wrong" one. At some point we should compare all parameters and if there is
88 // a report which parameters mach $_REQUEST then we should prefer that report
89 continue;
90 }
91 $mapApiToReport[$key] = get_class($report);
92 }
93 $cache->save($lazyCacheId, $mapApiToReport, $lifeTime = 3600);
94 }
95 return $mapApiToReport;
96 }
97 /**
98 * Returns a list of all available reports. Even not enabled reports will be returned. They will be already sorted
99 * depending on the order and category of the report.
100 * @return \Piwik\Plugin\Report[]
101 * @api
102 */
103 public function getAllReports()
104 {
105 $reports = $this->getAllReportClasses();
106 $cacheId = CacheId::siteAware(CacheId::languageAware('Reports' . md5(implode('', $reports))));
107 $cache = PiwikCache::getTransientCache();
108 if (!$cache->contains($cacheId)) {
109 $instances = array();
110 /**
111 * Triggered to add new reports that cannot be picked up automatically by the platform.
112 * This is useful if the plugin allows a user to create reports / dimensions dynamically. For example
113 * CustomDimensions or CustomVariables. There are a variable number of dimensions in this case and it
114 * wouldn't be really possible to create a report file for one of these dimensions as it is not known
115 * how many Custom Dimensions will exist.
116 *
117 * **Example**
118 *
119 * public function addReport(&$reports)
120 * {
121 * $reports[] = new MyCustomReport();
122 * }
123 *
124 * @param Report[] $reports An array of reports
125 */
126 Piwik::postEvent('Report.addReports', array(&$instances));
127 foreach ($reports as $report) {
128 $instances[] = new $report();
129 }
130 /**
131 * Triggered to filter / restrict reports.
132 *
133 * **Example**
134 *
135 * public function filterReports(&$reports)
136 * {
137 * foreach ($reports as $index => $report) {
138 * if ($report->getCategoryId() === 'General_Actions') {
139 * unset($reports[$index]); // remove all reports having this action
140 * }
141 * }
142 * }
143 *
144 * @param Report[] $reports An array of reports
145 */
146 Piwik::postEvent('Report.filterReports', array(&$instances));
147 @usort($instances, array($this, 'sort'));
148 $cache->save($cacheId, $instances);
149 }
150 return $cache->fetch($cacheId);
151 }
152 /**
153 * API metadata are sorted by category/name,
154 * with a little tweak to replicate the standard Piwik category ordering
155 *
156 * @param Report $a
157 * @param Report $b
158 * @return int
159 */
160 private function sort($a, $b)
161 {
162 $result = $this->compareCategories($a->getCategoryId(), $a->getSubcategoryId(), $a->getOrder(), $b->getCategoryId(), $b->getSubcategoryId(), $b->getOrder());
163 // if categories are equal, sort by ID
164 if (!$result) {
165 $aId = $a->getId();
166 $bId = $b->getId();
167 if ($aId == $bId) {
168 return 0;
169 }
170 return $aId < $bId ? -1 : 1;
171 }
172 return $result;
173 }
174 /**
175 * @param string|null $catIdA
176 * @param string|null $subcatIdA
177 * @param int $orderA
178 * @param string|null $catIdB
179 * @param string|null $subcatIdB
180 * @param int $orderB
181 *
182 * @return int
183 */
184 public function compareCategories($catIdA, $subcatIdA, $orderA, $catIdB, $subcatIdB, $orderB)
185 {
186 if (!isset($this->categoryList)) {
187 $this->categoryList = CategoryList::get();
188 }
189 $catA = $this->categoryList->getCategory($catIdA);
190 $catB = $this->categoryList->getCategory($catIdB);
191 // in case there is a category class for both reports
192 if (isset($catA) && isset($catB)) {
193 if ($catA->getOrder() == $catB->getOrder()) {
194 // same category order, compare subcategory order
195 $subcatA = $catA->getSubcategory($subcatIdA);
196 $subcatB = $catB->getSubcategory($subcatIdB);
197 // both reports have a subcategory with custom subcategory class
198 if ($subcatA && $subcatB) {
199 if ($subcatA->getOrder() == $subcatB->getOrder()) {
200 // same subcategory order, compare order of report
201 if ($orderA == $orderB) {
202 return 0;
203 }
204 return $orderA < $orderB ? -1 : 1;
205 }
206 return $subcatA->getOrder() < $subcatB->getOrder() ? -1 : 1;
207 } elseif ($subcatA) {
208 return 1;
209 } elseif ($subcatB) {
210 return -1;
211 }
212 if ($orderA == $orderB) {
213 return 0;
214 }
215 return $orderA < $orderB ? -1 : 1;
216 }
217 return $catA->getOrder() < $catB->getOrder() ? -1 : 1;
218 } elseif (isset($catA)) {
219 return -1;
220 } elseif (isset($catB)) {
221 return 1;
222 }
223 if ($catIdA === $catIdB) {
224 // both have same category, compare order
225 if ($orderA == $orderB) {
226 return 0;
227 }
228 return $orderA < $orderB ? -1 : 1;
229 }
230 return strnatcasecmp($catIdA ?? '', $catIdB ?? '');
231 }
232 /**
233 * Returns class names of all Report metadata classes.
234 *
235 * @return string[]
236 * @api
237 */
238 public function getAllReportClasses()
239 {
240 return Plugin\Manager::getInstance()->findMultipleComponents('Reports', '\\Piwik\\Plugin\\Report');
241 }
242 //Added this to trigger reset of category list as the list never gets rest after setting up due to isset check and affects testcases
243 public function unsetCategoryList()
244 {
245 unset($this->categoryList);
246 }
247 }
248