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