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