diff options
author | Thomas Steur <thomas.steur@googlemail.com> | 2014-06-11 07:04:53 +0400 |
---|---|---|
committer | Thomas Steur <thomas.steur@googlemail.com> | 2014-06-11 07:04:53 +0400 |
commit | 4f2e01d20a8027cf545613d883e4ef22267c1cc1 (patch) | |
tree | f065435c1eed3716d834f30886ceb95140214116 /core | |
parent | fca3bf825184cf0ddc3b9edcac0d90c95802afbf (diff) |
starting to refactor reports into classes, also refactored some more dimensions which is still not 100% working and needs more work
Diffstat (limited to 'core')
-rw-r--r-- | core/Db/Schema/Mysql.php | 10 | ||||
-rw-r--r-- | core/Menu/MenuReporting.php | 5 | ||||
-rw-r--r-- | core/Plugin/ActionDimension.php | 113 | ||||
-rw-r--r-- | core/Plugin/Report.php | 205 | ||||
-rw-r--r-- | core/Plugin/Segment.php | 123 | ||||
-rw-r--r-- | core/Plugin/ViewDataTable.php | 6 | ||||
-rw-r--r-- | core/Plugin/VisitDimension.php | 55 | ||||
-rw-r--r-- | core/Tracker/Visit.php | 55 | ||||
-rw-r--r-- | core/WidgetsList.php | 5 |
9 files changed, 521 insertions, 56 deletions
diff --git a/core/Db/Schema/Mysql.php b/core/Db/Schema/Mysql.php index a85fbe62d1..ef7d87b4dd 100644 --- a/core/Db/Schema/Mysql.php +++ b/core/Db/Schema/Mysql.php @@ -156,20 +156,12 @@ class Mysql implements SchemaInterface visitor_days_since_first SMALLINT(5) UNSIGNED NOT NULL, visit_first_action_time DATETIME NOT NULL, visit_last_action_time DATETIME NOT NULL, - visit_exit_idaction_url INTEGER(11) UNSIGNED NULL DEFAULT 0, - visit_exit_idaction_name INTEGER(11) UNSIGNED NOT NULL, - visit_entry_idaction_url INTEGER(11) UNSIGNED NOT NULL, - visit_entry_idaction_name INTEGER(11) UNSIGNED NOT NULL, visit_total_actions SMALLINT(5) UNSIGNED NOT NULL, visit_total_searches SMALLINT(5) UNSIGNED NOT NULL, visit_total_events SMALLINT(5) UNSIGNED NOT NULL, visit_total_time SMALLINT(5) UNSIGNED NOT NULL, visit_goal_converted TINYINT(1) NOT NULL, visit_goal_buyer TINYINT(1) NOT NULL, - referer_type TINYINT(1) UNSIGNED NULL, - referer_name VARCHAR(70) NULL, - referer_url TEXT NOT NULL, - referer_keyword VARCHAR(255) NULL, config_id BINARY(8) NOT NULL, config_resolution VARCHAR(9) NOT NULL, config_pdf TINYINT(1) NOT NULL, @@ -263,9 +255,7 @@ class Mysql implements SchemaInterface idvisitor BINARY(8) NOT NULL, server_time DATETIME NOT NULL, idvisit INTEGER(10) UNSIGNED NOT NULL, - idaction_url INTEGER(10) UNSIGNED DEFAULT NULL, idaction_url_ref INTEGER(10) UNSIGNED NULL DEFAULT 0, - idaction_name INTEGER(10) UNSIGNED, idaction_name_ref INTEGER(10) UNSIGNED NOT NULL, idaction_event_category INTEGER(10) UNSIGNED DEFAULT NULL, idaction_event_action INTEGER(10) UNSIGNED DEFAULT NULL, diff --git a/core/Menu/MenuReporting.php b/core/Menu/MenuReporting.php index 08dcc23e82..c30e04016b 100644 --- a/core/Menu/MenuReporting.php +++ b/core/Menu/MenuReporting.php @@ -8,6 +8,7 @@ */ namespace Piwik\Menu; use Piwik\Piwik; +use Piwik\Plugin\Report; /** * Contains menu entries for the Reporting menu (the menu displayed under the Piwik logo). @@ -70,6 +71,10 @@ class MenuReporting extends MenuAbstract foreach ($this->getAvailableMenus() as $menu) { $menu->configureReportingMenu($this); } + + foreach (Report::getAllReports() as $report) { + $report->configureReportingMenu($this); + } } return parent::getMenu(); diff --git a/core/Plugin/ActionDimension.php b/core/Plugin/ActionDimension.php new file mode 100644 index 0000000000..1380fae6bc --- /dev/null +++ b/core/Plugin/ActionDimension.php @@ -0,0 +1,113 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugin; + +use Piwik\Common; +use Piwik\Db; +use Piwik\Tracker\Request; +use Piwik\Plugin\Manager as PluginManager; + +/** + * @api + */ +abstract class ActionDimension +{ + protected $name; + + protected $fieldName = ''; + protected $fieldType = ''; + + protected $segments = array(); + + public function __construct() + { + $this->init(); + } + + protected function init() + { + + } + + public function install() + { + if (empty($this->fieldName) || empty($this->fieldType)) { + return; + } + + try { + $sql = "ALTER TABLE `" . Common::prefixTable("log_link_visit_action") . "` ADD `$this->fieldName` $this->fieldType"; + Db::exec($sql); + + } catch (\Exception $e) { + if (!Db::get()->isErrNo($e, '1060')) { + throw $e; + } + } + } + + public function shouldHandle() + { + return false; + } + + protected function addSegment(Segment $segment) + { + if (!empty($this->fieldName)) { + $segment->setSqlSegment('log_link_visit_action.' . $this->fieldName); + } + + $segment->setType('dimension'); + + $this->segments[] = $segment; + } + + /** + * @return Segment[] + */ + public function getSegments() + { + return $this->segments; + } + + public function getFieldName() + { + return $this->fieldName; + } + + abstract public function getName(); + + /** @return \Piwik\Plugin\ActionDimension[] */ + public static function getAllDimensions() + { + $plugins = PluginManager::getInstance()->getLoadedPlugins(); + $instances = array(); + foreach ($plugins as $plugin) { + foreach (self::getDimensions($plugin) as $instance) { + $instances[] = $instance; + } + } + + return $instances; + } + + /** @return \Piwik\Plugin\ActionDimension[] */ + public static function getDimensions(\Piwik\Plugin $plugin) + { + $dimensions = $plugin->findMultipleComponents('Columns', '\\Piwik\\Plugin\\ActionDimension'); + $instances = array(); + + foreach ($dimensions as $dimension) { + $instances[] = new $dimension(); + } + + return $instances; + } + +} diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php new file mode 100644 index 0000000000..b06ef0a828 --- /dev/null +++ b/core/Plugin/Report.php @@ -0,0 +1,205 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugin; + +use Piwik\API\Proxy; +use Piwik\Menu\MenuReporting; +use Piwik\Metrics; +use Piwik\Plugin\Manager as PluginManager; +use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; +use Piwik\WidgetsList; +use Piwik\ViewDataTable\Factory as ViewDataTableFactory; + +class Report +{ + protected $module; + protected $action; + protected $name; + protected $title; + protected $category; + protected $widgetTitle; + protected $menuTitle; + protected $processedMetrics = false; + protected $metrics = array(); + + /** + * @var \Piwik\Plugin\VisitDimension + */ + protected $dimension; + protected $documentation; + + /** + * @var null|Report + */ + protected $actionToLoadSubTables; + protected $order = 1; + + public function __construct() + { + $classname = get_class($this); + $parts = explode('\\', $classname); + $this->module = $parts[2]; + $this->action = lcfirst($parts[4]); + + $this->init(); + } + + protected function init() + { + } + + public function isEnabled() + { + return true; + } + + public function getDefaultTypeViewDataTable() + { + return HtmlTable::ID; + } + + public function configureView(ViewDataTable $view) + { + + } + + public function render() + { + $apiProxy = Proxy::getInstance(); + + if (!$apiProxy->isExistingApiAction($this->module, $this->action)) { + throw new \Exception("Invalid action name '$this->action' for '$this->module' plugin."); + } + + $apiAction = $apiProxy->buildApiActionName($this->module, $this->action); + + $view = ViewDataTableFactory::build(null, $apiAction, 'CoreHome.renderWidget'); + $rendered = $view->render(); + + return $rendered; + } + + public function configureWidget(WidgetsList $widget) + { + if ($this->widgetTitle) { + $widget->add($this->category, $this->widgetTitle, 'CoreHome', 'renderWidget', array('reportModule' => $this->module, 'reportAction' => $this->action)); + } + } + + public function configureReportingMenu(MenuReporting $menu) + { + if ($this->menuTitle) { + $menu->add($this->category, + $this->menuTitle, + array('module' => 'CoreHome', 'action' => 'renderMenuReport', 'reportModule' => $this->module, 'reportAction' => $this->action), + $this->isEnabled(), + $this->order); + } + } + + protected function getMetrics() + { + // TODO not all will be defined there... later in Columns directory + $translations = Metrics::getDefaultMetricTranslations(); + $metrics = array(); + + foreach ($this->metrics as $metric) { + if (!empty( $translations[$metric])) { + $metric[$metric] = $translations[$metric]; + } else { + $metric[$metric] = 'To be defined'; + } + } + + return $metrics; + } + + protected function getMetricsDocumentation() + { + // TODO not all will be defined there... later in Columns directory + $translations = Metrics::getDefaultMetricsDocumentation(); + $documentation = array(); + + foreach ($this->metrics as $metric) { + if (!empty( $translations[$metric])) { + $metric[$metric] = $translations[$metric]; + } else { + $metric[$metric] = 'To be defined see todo'; + } + } + + return $documentation; + } + + public function toArray() + { + $report = array( + 'category' => $this->category, + 'name' => $this->name, + 'module' => $this->module, + 'action' => $this->action, + 'metrics' => $this->getMetrics(), + 'metricsDocumentation' => $this->getMetricsDocumentation(), + 'documentation' => $this->documentation, + 'processedMetrics' => $this->processedMetrics, + 'order' => $this->order + ); + + if (!empty($this->dimension)) { + $report['dimension'] = $this->dimension->getName(); + } + + if (!empty($this->actionToLoadSubTables)) { + $report['actionToLoadSubTables'] = $this->actionToLoadSubTables; + } + + return $report; + } + + public function getName() + { + return $this->name; + } + + public function getAction() + { + return $this->action; + } + + public static function factory($moduleOnlyOrModuleAndAction, $action = '') + { + if (empty($action) && strpos($moduleOnlyOrModuleAndAction, '.') > 0) { + $parts = explode('.', $moduleOnlyOrModuleAndAction); + $module = $parts[0]; + $action = $parts[1]; + } else { + $module = $moduleOnlyOrModuleAndAction; + } + + foreach (self::getAllReports() as $report) { + if ($report->module === $module && $report->action === $action) { + return $report; + } + } + } + + /** @return \Piwik\Plugin\Report[] */ + public static function getAllReports() + { + $reports = PluginManager::getInstance()->findMultipleComponents('Reports', '\\Piwik\\Plugin\\Report'); + $instances = array(); + + foreach ($reports as $report) { + $instances[] = new $report(); + } + + return $instances; + } + +} diff --git a/core/Plugin/Segment.php b/core/Plugin/Segment.php new file mode 100644 index 0000000000..41933a142b --- /dev/null +++ b/core/Plugin/Segment.php @@ -0,0 +1,123 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugin; + +/** + * @api + */ +class Segment +{ + private $type; + private $category; + private $name; + private $segment; + private $sqlSegment; + private $sqlFilter; + private $sqlFilterValue; + private $acceptValues; + + public function __construct() + { + $this->init(); + } + + protected function init() + { + + } + + /** + * @param mixed $acceptValues + */ + public function setAcceptValues($acceptValues) + { + $this->acceptValues = $acceptValues; + } + + /** + * @param mixed $category + */ + public function setCategory($category) + { + $this->category = $category; + } + + /** + * @param mixed $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @param mixed $segment + */ + public function setSegment($segment) + { + $this->segment = $segment; + } + + /** + * @param mixed $sqlFilter + */ + public function setSqlFilter($sqlFilter) + { + $this->sqlFilter = $sqlFilter; + } + + /** + * @param mixed $sqlFilterValue + */ + public function setSqlFilterValue($sqlFilterValue) + { + $this->sqlFilterValue = $sqlFilterValue; + } + + /** + * @param mixed $sqlSegment + */ + public function setSqlSegment($sqlSegment) + { + $this->sqlSegment = $sqlSegment; + } + + /** + * @param mixed $type + */ + public function setType($type) + { + $this->type = $type; + } + + public function toArray() + { + $segment = array( + 'type' => $this->type, + 'category' => $this->category, + 'name' => $this->name, + 'segment' => $this->segment, + 'sqlSegment' => $this->sqlSegment, + ); + + if (!empty($this->sqlFilter)) { + $segment['sqlFilter'] = $this->sqlFilter; + } + + if (!empty($this->sqlFilterValue)) { + $segment['sqlFilterValue'] = $this->sqlFilterValue; + } + + if (!empty($this->acceptValues)) { + $segment['acceptedValues'] = $this->acceptValues; + } + + return $segment; + } +} diff --git a/core/Plugin/ViewDataTable.php b/core/Plugin/ViewDataTable.php index 1643fd03ee..eb821dcb5c 100644 --- a/core/Plugin/ViewDataTable.php +++ b/core/Plugin/ViewDataTable.php @@ -191,6 +191,12 @@ abstract class ViewDataTable implements ViewInterface $this->requestConfig->apiMethodToRequestDataTable = $apiMethodToRequestDataTable; + $report = Report::factory($this->requestConfig->apiMethodToRequestDataTable); + + if (!empty($report)) { + $report->configureView($this); + } + /** * Triggered during {@link ViewDataTable} construction. Subscribers should customize * the view based on the report that is being displayed. diff --git a/core/Plugin/VisitDimension.php b/core/Plugin/VisitDimension.php index 73b454305c..b24420daad 100644 --- a/core/Plugin/VisitDimension.php +++ b/core/Plugin/VisitDimension.php @@ -20,15 +20,27 @@ abstract class VisitDimension { protected $name; - protected $trackerParam = ''; - protected $trackerType = ''; - protected $trackerDefault = ''; - protected $fieldName = ''; protected $fieldType = ''; + protected $segments = array(); + + public function __construct() + { + $this->init(); + } + + protected function init() + { + + } + public function install() { + if (empty($this->fieldName) || empty($this->fieldType)) { + return; + } + try { $sql = "ALTER TABLE `" . Common::prefixTable("log_visit") . "` ADD `$this->fieldName` $this->fieldType"; Db::exec($sql); @@ -40,12 +52,23 @@ abstract class VisitDimension } } - public function onNewVisit(Request $request, $visit) + protected function addSegment(Segment $segment) { - $params = array(); - // TODO $params = $request->getParams() - $value = Common::getRequestVar($this->trackerParam, $this->trackerDefault, $this->trackerType, $params); - return $value; + if (!empty($this->fieldName)) { + $segment->setSqlSegment('log_visit.' . $this->fieldName); + } + + $segment->setType('dimension'); + + $this->segments[] = $segment; + } + + /** + * @return Segment[] + */ + public function getSegments() + { + return $this->segments; } public function getFieldName() @@ -58,12 +81,12 @@ abstract class VisitDimension /** @return \Piwik\Plugin\VisitDimension[] */ public static function getAllDimensions() { - $manager = PluginManager::getInstance(); - $dimensions = $manager->findMultipleComponents('Dimensions', '\\Piwik\\Plugin\\VisitDimension'); - $instances = array(); - - foreach ($dimensions as $dimension) { - $instances[] = new $dimension(); + $plugins = PluginManager::getInstance()->getLoadedPlugins(); + $instances = array(); + foreach ($plugins as $plugin) { + foreach (self::getDimensions($plugin) as $instance) { + $instances[] = $instance; + } } return $instances; @@ -72,7 +95,7 @@ abstract class VisitDimension /** @return \Piwik\Plugin\VisitDimension[] */ public static function getDimensions(\Piwik\Plugin $plugin) { - $dimensions = $plugin->findMultipleComponents('Dimensions', '\\Piwik\\Plugin\\VisitDimension'); + $dimensions = $plugin->findMultipleComponents('Columns', '\\Piwik\\Plugin\\VisitDimension'); $instances = array(); foreach ($dimensions as $dimension) { diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php index 5174b48882..15950702fe 100644 --- a/core/Tracker/Visit.php +++ b/core/Tracker/Visit.php @@ -93,9 +93,9 @@ class Visit implements VisitInterface /** * Triggered after visits are tested for exclusion so plugins can modify the IP address * persisted with a visit. - * + * * This event is primarily used by the **PrivacyManager** plugin to anonymize IP addresses. - * + * * @param string &$ip The visitor's IP address. */ Piwik::postEvent('Tracker.setVisitorIp', array(&$this->visitorInfo['location_ip'])); @@ -253,10 +253,10 @@ class Visit implements VisitInterface /** * Triggered before a [visit entity](/guides/persistence-and-the-mysql-backend#visits) is updated when * tracking an action for an existing visit. - * + * * This event can be used to modify the visit properties that will be updated before the changes * are persisted. - * + * * @param array &$valuesToUpdate Visit entity properties that will be updated. * @param array $visit The entire visit entity. Read [this](/guides/persistence-and-the-mysql-backend#visits) * to see what it contains. @@ -307,7 +307,7 @@ class Visit implements VisitInterface /** * Triggered before a new [visit entity](/guides/persistence-and-the-mysql-backend#visits) is persisted. - * + * * This event can be used to modify the visit entity or add new information to it before it is persisted. * The UserCountry plugin, for example, uses this event to add location information for each visit. * @@ -319,7 +319,10 @@ class Visit implements VisitInterface $dimensions = VisitDimension::getAllDimensions(); foreach ($dimensions as $dimension) { - $this->visitorInfo[$dimension->getFieldName()] = $dimension->onNewVisit($this->request, $this->visitorInfo); + if (!method_exists($dimension, 'onNewVisit')) { + continue; + } + $this->visitorInfo[$dimension->getFieldName()] = $dimension->onNewVisit($this->request, $this->visitorInfo, $action); } $this->request->overrideLocation($this->visitorInfo); @@ -505,10 +508,8 @@ class Visit implements VisitInterface protected function getNewVisitorInformation($action) { - $actionType = $idActionName = $idActionUrl = false; + $actionType = false; if($action) { - $idActionUrl = $action->getIdActionUrlForEntryAndExitIds(); - $idActionName = $action->getIdActionNameForEntryAndExitIds(); $actionType = $action->getActionType(); } @@ -527,12 +528,6 @@ class Visit implements VisitInterface $userInfo = $this->getSettingsObject(); $userInfo = $userInfo->getInfo(); - // Referrer data - $referrer = new Referrer(); - $referrerUrl = $this->request->getParam('urlref'); - $currentUrl = $this->request->getParam('url'); - $referrerInfo = $referrer->getReferrerInformation($referrerUrl, $currentUrl, $this->request->getIdSite()); - $visitorReturning = $isReturningCustomer ? 2 /* Returning customer */ : ($visitCount > 1 || $this->isVisitorKnown() || $daysSinceLastVisit > 0 @@ -551,10 +546,6 @@ class Visit implements VisitInterface 'visitor_days_since_first' => $daysSinceFirstVisit, 'visit_first_action_time' => Tracker::getDatetimeFromTimestamp($this->request->getCurrentTimestamp()), 'visit_last_action_time' => Tracker::getDatetimeFromTimestamp($this->request->getCurrentTimestamp()), - 'visit_entry_idaction_url' => (int)$idActionUrl, - 'visit_entry_idaction_name' => (int)$idActionName, - 'visit_exit_idaction_url' => (int)$idActionUrl, - 'visit_exit_idaction_name' => (int)$idActionName, 'visit_total_actions' => in_array($actionType, array(Action::TYPE_PAGE_URL, Action::TYPE_DOWNLOAD, @@ -566,10 +557,6 @@ class Visit implements VisitInterface 'visit_total_events' => $actionType == Action::TYPE_EVENT ? 1 : 0, 'visit_total_time' => self::cleanupVisitTotalTime($defaultTimeOnePageVisit), 'visit_goal_buyer' => $this->goalManager->getBuyerType(), - 'referer_type' => $referrerInfo['referer_type'], - 'referer_name' => $referrerInfo['referer_name'], - 'referer_url' => $referrerInfo['referer_url'], - 'referer_keyword' => $referrerInfo['referer_keyword'], 'config_id' => $userInfo['config_id'], 'config_resolution' => $userInfo['config_resolution'], 'config_pdf' => $userInfo['config_pdf'], @@ -599,19 +586,15 @@ class Visit implements VisitInterface $valuesToUpdate = array(); if ($action) { + $actionType = $action->getActionType(); $idActionUrl = $action->getIdActionUrlForEntryAndExitIds(); - $idActionName = $action->getIdActionNameForEntryAndExitIds(); - $actionType = $action->getActionType(); - - if ($idActionName !== false) { - $valuesToUpdate['visit_exit_idaction_name'] = $idActionName; - } $incrementActions = false; + if ($idActionUrl !== false) { - $valuesToUpdate['visit_exit_idaction_url'] = $idActionUrl; $incrementActions = true; } + if ($actionType == Action::TYPE_SITE_SEARCH) { $valuesToUpdate['visit_total_searches'] = 'visit_total_searches + 1'; $incrementActions = true; @@ -659,6 +642,18 @@ class Visit implements VisitInterface $valuesToUpdate['visit_goal_buyer'] = $visitEcommerceStatus; } + $dimensions = VisitDimension::getAllDimensions(); + foreach ($dimensions as $dimension) { + if (!method_exists($dimension, 'onExistingVisit')) { + continue; + } + $value = $dimension->onExistingVisit($this->request, $this->visitorInfo, $action); + + if (false !== $value) { + $valuesToUpdate[$dimension->getFieldName()] = $value; + } + } + // Custom Variables overwrite previous values on each page view $valuesToUpdate = array_merge($valuesToUpdate, $this->visitorCustomVariables); return $valuesToUpdate; diff --git a/core/WidgetsList.php b/core/WidgetsList.php index 095c54cfd7..4051d8948a 100644 --- a/core/WidgetsList.php +++ b/core/WidgetsList.php @@ -9,6 +9,7 @@ namespace Piwik; use Piwik\Plugin\Manager as PluginManager; +use Piwik\Plugin\Report; /** * Manages the global list of reports that can be displayed as dashboard widgets. @@ -83,6 +84,10 @@ class WidgetsList extends Singleton $widgets = PluginManager::getInstance()->findComponents('Widgets', 'Piwik\\Plugin\\Widgets'); $widgetsList = self::getInstance(); + foreach (Report::getAllReports() as $report) { + $report->configureWidget($widgetsList); + } + foreach ($widgets as $widget) { $widget->configure($widgetsList); } |