PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.2.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.2.2
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 / ViewDataTable / Manager.php
matomo / app / core / ViewDataTable Last commit date
Config.php 1 year ago Factory.php 1 year ago Manager.php 1 year ago Request.php 1 year ago RequestConfig.php 1 year ago
Manager.php
341 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\ViewDataTable;
10
11 use Piwik\Cache;
12 use Piwik\Common;
13 use Piwik\Option;
14 use Piwik\Piwik;
15 use Piwik\Plugin\Report;
16 use Piwik\Plugin\ViewDataTable;
17 use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud;
18 use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable;
19 use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Bar;
20 use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Pie;
21 use Piwik\Plugins\Goals\Visualizations\Goals;
22 use Piwik\Plugins\Insights\Visualizations\Insight;
23 use Piwik\Plugin\Manager as PluginManager;
24 /**
25 * ViewDataTable Manager.
26 *
27 */
28 class Manager
29 {
30 /**
31 * Returns the viewDataTable IDs of a visualization's class lineage.
32 *
33 * @see self::getVisualizationClassLineage
34 *
35 * @param string $klass The visualization class.
36 *
37 * @return array
38 */
39 public static function getIdsWithInheritance($klass)
40 {
41 $klasses = Common::getClassLineage($klass);
42 $result = array();
43 foreach ($klasses as $klass) {
44 try {
45 $result[] = $klass::getViewDataTableId();
46 } catch (\Exception $e) {
47 // in case $klass did not define an id: eg Plugin\ViewDataTable
48 continue;
49 }
50 }
51 return $result;
52 }
53 /**
54 * Returns all registered visualization classes. Uses the 'Visualization.getAvailable'
55 * event to retrieve visualizations.
56 *
57 * @return array Array mapping visualization IDs with their associated visualization classes.
58 * @throws \Exception If a visualization class does not exist or if a duplicate visualization ID
59 * is found.
60 * @return array
61 */
62 public static function getAvailableViewDataTables()
63 {
64 $cache = Cache::getTransientCache();
65 $cacheId = 'ViewDataTable.getAvailableViewDataTables';
66 $dataTables = $cache->fetch($cacheId);
67 if (!empty($dataTables)) {
68 return $dataTables;
69 }
70 $klassToExtend = '\\Piwik\\Plugin\\ViewDataTable';
71 /** @var string[] $visualizations */
72 $visualizations = PluginManager::getInstance()->findMultipleComponents('Visualizations', $klassToExtend);
73 $result = array();
74 foreach ($visualizations as $viz) {
75 if (!class_exists($viz)) {
76 throw new \Exception("Invalid visualization class '{$viz}' found in Visualization.getAvailableVisualizations.");
77 }
78 if (!is_subclass_of($viz, $klassToExtend)) {
79 throw new \Exception("ViewDataTable class '{$viz}' does not extend Plugin/ViewDataTable");
80 }
81 $vizId = $viz::getViewDataTableId();
82 if (isset($result[$vizId])) {
83 throw new \Exception("ViewDataTable ID '{$vizId}' is already in use!");
84 }
85 $result[$vizId] = $viz;
86 }
87 /**
88 * Triggered to filter available DataTable visualizations.
89 *
90 * Plugins that want to disable certain visualizations should subscribe to
91 * this event and remove visualizations from the incoming array.
92 *
93 * **Example**
94 *
95 * public function filterViewDataTable(&$visualizations)
96 * {
97 * unset($visualizations[HtmlTable::ID]);
98 * }
99 *
100 * @param array &$visualizations An array of all available visualizations indexed by visualization ID.
101 * @since Piwik 3.0.0
102 */
103 Piwik::postEvent('ViewDataTable.filterViewDataTable', array(&$result));
104 $cache->save($cacheId, $result);
105 return $result;
106 }
107 /**
108 * Returns all available visualizations that are not part of the CoreVisualizations plugin.
109 *
110 * @return array Array mapping visualization IDs with their associated visualization classes.
111 */
112 public static function getNonCoreViewDataTables()
113 {
114 $result = array();
115 foreach (static::getAvailableViewDataTables() as $vizId => $vizClass) {
116 if (\false === strpos($vizClass, 'Piwik\\Plugins\\CoreVisualizations') && \false === strpos($vizClass, 'Piwik\\Plugins\\Goals\\Visualizations\\Goals')) {
117 $result[$vizId] = $vizClass;
118 }
119 }
120 return $result;
121 }
122 /**
123 * This method determines the default set of footer icons to display below a report.
124 *
125 * $result has the following format:
126 *
127 * ```
128 * array(
129 * array( // footer icon group 1
130 * 'class' => 'footerIconGroup1CssClass',
131 * 'buttons' => array(
132 * 'id' => 'myid',
133 * 'title' => 'My Tooltip',
134 * 'icon' => 'path/to/my/icon.png'
135 * )
136 * ),
137 * array( // footer icon group 2
138 * 'class' => 'footerIconGroup2CssClass',
139 * 'buttons' => array(...)
140 * ),
141 * ...
142 * )
143 * ```
144 */
145 public static function configureFooterIcons(ViewDataTable $view)
146 {
147 $result = array();
148 $normalViewIcons = self::getNormalViewIcons($view);
149 if (!empty($normalViewIcons['buttons'])) {
150 $result[] = $normalViewIcons;
151 }
152 // add insight views
153 $insightsViewIcons = array('class' => 'tableInsightViews', 'buttons' => array());
154 $graphViewIcons = self::getGraphViewIcons($view);
155 $nonCoreVisualizations = static::getNonCoreViewDataTables();
156 foreach ($nonCoreVisualizations as $id => $klass) {
157 if ($klass::canDisplayViewDataTable($view) || $view::ID == $id) {
158 $footerIcon = static::getFooterIconFor($id);
159 if (Insight::ID == $footerIcon['id']) {
160 $insightsViewIcons['buttons'][] = static::getFooterIconFor($id);
161 } else {
162 $graphViewIcons['buttons'][] = static::getFooterIconFor($id);
163 }
164 }
165 }
166 $graphViewIcons['buttons'] = array_filter($graphViewIcons['buttons']);
167 if (!empty($insightsViewIcons['buttons']) && $view->config->show_insights) {
168 $result[] = $insightsViewIcons;
169 }
170 if (!empty($graphViewIcons['buttons'])) {
171 $result[] = $graphViewIcons;
172 }
173 return $result;
174 }
175 /**
176 * Returns an array with information necessary for adding the viewDataTable to the footer.
177 *
178 * @param string $viewDataTableId
179 *
180 * @return array
181 */
182 private static function getFooterIconFor($viewDataTableId)
183 {
184 $tables = static::getAvailableViewDataTables();
185 if (!array_key_exists($viewDataTableId, $tables)) {
186 return;
187 }
188 $klass = $tables[$viewDataTableId];
189 return array('id' => $klass::getViewDataTableId(), 'title' => Piwik::translate($klass::FOOTER_ICON_TITLE), 'icon' => $klass::FOOTER_ICON);
190 }
191 public static function clearAllViewDataTableParameters()
192 {
193 Option::deleteLike('viewDataTableParameters_%');
194 }
195 public static function clearUserViewDataTableParameters($userLogin)
196 {
197 Option::deleteLike('viewDataTableParameters_' . $userLogin . '_%');
198 }
199 public static function getViewDataTableParameters($login, $controllerAction, $containerId = null)
200 {
201 $paramsKey = self::buildViewDataTableParametersOptionKey($login, $controllerAction, $containerId);
202 $params = Option::get($paramsKey);
203 if (empty($params)) {
204 return array();
205 }
206 $params = json_decode($params);
207 $params = (array) $params;
208 // when setting an invalid parameter, we silently ignore the invalid parameter and proceed
209 $params = self::removeNonOverridableParameters($controllerAction, $params);
210 self::unsetComparisonParams($params);
211 return $params;
212 }
213 /**
214 * Any parameter set here will be set into one of the following objects:
215 *
216 * - ViewDataTable.requestConfig[paramName]
217 * - ViewDataTable.config.custom_parameters[paramName]
218 * - ViewDataTable.config.custom_parameters[paramName]
219 *
220 * (see ViewDataTable::overrideViewPropertiesWithParams)
221 * @param $login
222 * @param $controllerAction
223 * @param $parametersToOverride
224 * @param string|null $containerId
225 * @throws \Exception
226 */
227 public static function saveViewDataTableParameters($login, $controllerAction, $parametersToOverride, $containerId = null)
228 {
229 $params = self::getViewDataTableParameters($login, $controllerAction);
230 self::unsetComparisonParams($params);
231 foreach ($parametersToOverride as $key => $value) {
232 if ($key === 'viewDataTable' && !empty($params[$key]) && $params[$key] !== $value) {
233 if (!empty($params['columns'])) {
234 unset($params['columns']);
235 }
236 if (!empty($params['columns_to_display'])) {
237 unset($params['columns_to_display']);
238 }
239 }
240 $params[$key] = $value;
241 }
242 $paramsKey = self::buildViewDataTableParametersOptionKey($login, $controllerAction, $containerId);
243 // when setting an invalid parameter, we fail and let user know
244 self::errorWhenSettingNonOverridableParameter($controllerAction, $params);
245 Option::set($paramsKey, json_encode($params));
246 }
247 private static function buildViewDataTableParametersOptionKey($login, $controllerAction, $containerId)
248 {
249 $result = sprintf('viewDataTableParameters_%s_%s', $login, $controllerAction);
250 if (!empty($containerId)) {
251 $result .= '_' . $containerId;
252 }
253 return $result;
254 }
255 /**
256 * Display a meaningful error message when any invalid parameter is being set.
257 *
258 * @param $params
259 * @throws
260 */
261 private static function errorWhenSettingNonOverridableParameter($controllerAction, $params)
262 {
263 $viewDataTable = self::makeTemporaryViewDataTableInstance($controllerAction, $params);
264 $viewDataTable->throwWhenSettingNonOverridableParameter($params);
265 }
266 private static function removeNonOverridableParameters($controllerAction, $params)
267 {
268 $viewDataTable = self::makeTemporaryViewDataTableInstance($controllerAction, $params);
269 $nonOverridableParams = $viewDataTable->getNonOverridableParams($params);
270 foreach ($params as $key => $value) {
271 if (in_array($key, $nonOverridableParams)) {
272 unset($params[$key]);
273 }
274 }
275 return $params;
276 }
277 /**
278 * @param $controllerAction
279 * @param $params
280 * @return ViewDataTable
281 * @throws \Exception
282 */
283 private static function makeTemporaryViewDataTableInstance($controllerAction, $params)
284 {
285 $report = new Report();
286 $viewDataTableType = isset($params['viewDataTable']) ? $params['viewDataTable'] : $report->getDefaultTypeViewDataTable();
287 $apiAction = $controllerAction;
288 $loadViewDataTableParametersForUser = \false;
289 $viewDataTable = \Piwik\ViewDataTable\Factory::build($viewDataTableType, $apiAction, $controllerAction, $forceDefault = \false, $loadViewDataTableParametersForUser);
290 return $viewDataTable;
291 }
292 private static function getNormalViewIcons(ViewDataTable $view)
293 {
294 // add normal view icons (eg, normal table, all columns, goals)
295 $normalViewIcons = array('class' => 'tableAllColumnsSwitch', 'buttons' => array());
296 if ($view->config->show_table) {
297 $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable::ID);
298 }
299 if ($view->config->show_table_all_columns) {
300 $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable\AllColumns::ID);
301 }
302 if ($view->config->show_goals) {
303 $goalButton = static::getFooterIconFor(Goals::ID);
304 if (Common::getRequestVar('idGoal', \false) == 'ecommerceOrder') {
305 $goalButton['icon'] = 'icon-ecommerce-order';
306 }
307 $normalViewIcons['buttons'][] = $goalButton;
308 }
309 if ($view->config->show_ecommerce) {
310 $normalViewIcons['buttons'][] = array('id' => 'ecommerceOrder', 'title' => Piwik::translate('General_EcommerceOrders'), 'icon' => 'icon-ecommerce-order', 'text' => Piwik::translate('General_EcommerceOrders'));
311 $normalViewIcons['buttons'][] = array('id' => 'ecommerceAbandonedCart', 'title' => Piwik::translate('General_AbandonedCarts'), 'icon' => 'icon-ecommerce-abandoned-cart', 'text' => Piwik::translate('General_AbandonedCarts'));
312 }
313 $normalViewIcons['buttons'] = array_filter($normalViewIcons['buttons']);
314 return $normalViewIcons;
315 }
316 private static function getGraphViewIcons(ViewDataTable $view)
317 {
318 // add graph views
319 $graphViewIcons = array('class' => 'tableGraphViews', 'buttons' => array());
320 if ($view->config->show_all_views_icons) {
321 if ($view->config->show_bar_chart) {
322 $graphViewIcons['buttons'][] = static::getFooterIconFor(Bar::ID);
323 }
324 if ($view->config->show_pie_chart) {
325 $graphViewIcons['buttons'][] = static::getFooterIconFor(Pie::ID);
326 }
327 if ($view->config->show_tag_cloud) {
328 $graphViewIcons['buttons'][] = static::getFooterIconFor(Cloud::ID);
329 }
330 }
331 return $graphViewIcons;
332 }
333 private static function unsetComparisonParams(&$params)
334 {
335 unset($params['compareDates']);
336 unset($params['comparePeriods']);
337 unset($params['compareSegments']);
338 unset($params['compare']);
339 }
340 }
341