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