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