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 / ViewDataTable / Manager.php
matomo / app / core / ViewDataTable Last commit date
Config.php 2 weeks ago Factory.php 1 year ago Manager.php 3 months ago Request.php 6 months ago RequestConfig.php 2 weeks ago
Manager.php
340 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 $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 * @throws
259 */
260 private static function errorWhenSettingNonOverridableParameter($controllerAction, $params)
261 {
262 $viewDataTable = self::makeTemporaryViewDataTableInstance($controllerAction, $params);
263 $viewDataTable->throwWhenSettingNonOverridableParameter($params);
264 }
265 private static function removeNonOverridableParameters($controllerAction, $params)
266 {
267 $viewDataTable = self::makeTemporaryViewDataTableInstance($controllerAction, $params);
268 $nonOverridableParams = $viewDataTable->getNonOverridableParams($params);
269 foreach ($params as $key => $value) {
270 if (in_array($key, $nonOverridableParams)) {
271 unset($params[$key]);
272 }
273 }
274 return $params;
275 }
276 /**
277 * @param $controllerAction
278 * @param $params
279 * @return ViewDataTable
280 * @throws \Exception
281 */
282 private static function makeTemporaryViewDataTableInstance($controllerAction, $params)
283 {
284 $report = new Report();
285 $viewDataTableType = isset($params['viewDataTable']) ? $params['viewDataTable'] : $report->getDefaultTypeViewDataTable();
286 $apiAction = $controllerAction;
287 $loadViewDataTableParametersForUser = \false;
288 $viewDataTable = \Piwik\ViewDataTable\Factory::build($viewDataTableType, $apiAction, $controllerAction, $forceDefault = \false, $loadViewDataTableParametersForUser);
289 return $viewDataTable;
290 }
291 private static function getNormalViewIcons(ViewDataTable $view)
292 {
293 // add normal view icons (eg, normal table, all columns, goals)
294 $normalViewIcons = array('class' => 'tableAllColumnsSwitch', 'buttons' => array());
295 if ($view->config->show_table) {
296 $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable::ID);
297 }
298 if ($view->config->show_table_all_columns) {
299 $normalViewIcons['buttons'][] = static::getFooterIconFor(HtmlTable\AllColumns::ID);
300 }
301 if ($view->config->show_goals) {
302 $goalButton = static::getFooterIconFor(Goals::ID);
303 if (Common::getRequestVar('idGoal', \false) == 'ecommerceOrder') {
304 $goalButton['icon'] = 'icon-ecommerce-order';
305 }
306 $normalViewIcons['buttons'][] = $goalButton;
307 }
308 if ($view->config->show_ecommerce) {
309 $normalViewIcons['buttons'][] = array('id' => 'ecommerceOrder', 'title' => Piwik::translate('General_EcommerceOrders'), 'icon' => 'icon-ecommerce-order', 'text' => Piwik::translate('General_EcommerceOrders'));
310 $normalViewIcons['buttons'][] = array('id' => 'ecommerceAbandonedCart', 'title' => Piwik::translate('General_AbandonedCarts'), 'icon' => 'icon-ecommerce-abandoned-cart', 'text' => Piwik::translate('General_AbandonedCarts'));
311 }
312 $normalViewIcons['buttons'] = array_filter($normalViewIcons['buttons']);
313 return $normalViewIcons;
314 }
315 private static function getGraphViewIcons(ViewDataTable $view)
316 {
317 // add graph views
318 $graphViewIcons = array('class' => 'tableGraphViews', 'buttons' => array());
319 if ($view->config->show_all_views_icons) {
320 if ($view->config->show_bar_chart) {
321 $graphViewIcons['buttons'][] = static::getFooterIconFor(Bar::ID);
322 }
323 if ($view->config->show_pie_chart) {
324 $graphViewIcons['buttons'][] = static::getFooterIconFor(Pie::ID);
325 }
326 if ($view->config->show_tag_cloud) {
327 $graphViewIcons['buttons'][] = static::getFooterIconFor(Cloud::ID);
328 }
329 }
330 return $graphViewIcons;
331 }
332 private static function unsetComparisonParams(&$params)
333 {
334 unset($params['compareDates']);
335 unset($params['comparePeriods']);
336 unset($params['compareSegments']);
337 unset($params['compare']);
338 }
339 }
340