$posPrevious) { $action = $actionType; } } if (!empty($action)) { return $action; } return new ActionPageview($request); } private static function getPriority(Action $actionType) { $key = array_search($actionType->getActionType(), self::$factoryPriority); if (false === $key) { return -1; } return $key; } public static function shouldHandle(Request $request) { return false; } private static function getAllActions(Request $request) { static $actions; if (is_null($actions)) { $actions = Manager::getInstance()->findMultipleComponents('Actions', '\\Piwik\\Tracker\\Action'); } $instances = array(); foreach ($actions as $action) { /** @var \Piwik\Tracker\Action $action */ if ($action::shouldHandle($request)) { $instances[] = new $action($request); } } return $instances; } public function __construct($type, Request $request) { $this->actionType = $type; $this->request = $request; } /** * Returns URL of the page currently being tracked, or the file being downloaded, or the outlink being clicked * * @return string */ public function getActionUrl() { return $this->actionUrl; } /** * Returns URL of page being tracked, including all original Query parameters */ public function getActionUrlRaw() { return $this->rawActionUrl; } public function getActionName() { return $this->actionName; } public function getActionType() { return $this->actionType; } public function getCustomVariables() { return $this->request->getCustomVariables($scope = 'page'); } // custom_float column public function getCustomFloatValue() { return false; } protected function setActionName($name) { $this->actionName = PageUrl::cleanupString((string)$name); } protected function setActionUrl($url) { $this->rawActionUrl = PageUrl::getUrlIfLookValid($url); $url = PageUrl::excludeQueryParametersFromUrl($url, $this->request->getIdSite()); $this->actionUrl = PageUrl::getUrlIfLookValid($url); if ($url != $this->rawActionUrl) { Common::printDebug(' Before was "' . $this->rawActionUrl . '"'); Common::printDebug(' After is "' . $url . '"'); } } protected function setActionUrlWithoutExcludingParameters($url) { $url = PageUrl::getUrlIfLookValid($url); $this->rawActionUrl = $url; $this->actionUrl = $url; } abstract protected function getActionsToLookup(); protected function getUrlAndType() { $url = $this->getActionUrl(); if (!empty($url)) { // normalize urls by stripping protocol and www $url = PageUrl::normalizeUrl($url); return array($url['url'], self::TYPE_PAGE_URL, $url['prefixId']); } return false; } public function getIdActionUrl() { $idUrl = $this->actionIdsCached['idaction_url']; // note; idaction_url = 0 is displayed as "Page URL Not Defined" return (int)$idUrl; } public function getIdActionUrlForEntryAndExitIds() { return $this->getIdActionUrl(); } public function getIdActionNameForEntryAndExitIds() { return $this->getIdActionName(); } public function getIdActionName() { if (!isset($this->actionIdsCached['idaction_name'])) { return false; } return $this->actionIdsCached['idaction_name']; } /** * Returns the ID of the newly created record in the log_link_visit_action table * * @return int */ public function getIdLinkVisitAction() { return $this->idLinkVisitAction; } public static function getTypeAsString($type) { $class = new \ReflectionClass("\\Piwik\\Tracker\\Action"); $constants = $class->getConstants(); $typeId = array_search($type, $constants); if (false === $typeId) { throw new Exception("Unexpected action type " . $type); } return str_replace('TYPE_', '', $typeId); } /** * Loads the idaction of the current action name and the current action url. * These idactions are used in the visitor logging table to link the visit information * (entry action, exit action) to the actions. * These idactions are also used in the table that links the visits and their actions. * * The methods takes care of creating a new record(s) in the action table if the existing * action name and action url doesn't exist yet. */ public function loadIdsFromLogActionTable() { if (!empty($this->actionIdsCached)) { return; } /** @var ActionDimension[] $dimensions */ $dimensions = ActionDimension::getAllDimensions(); $actions = $this->getActionsToLookup(); foreach ($dimensions as $dimension) { $value = $dimension->onLookupAction($this->request, $this); if (false !== $value) { if (is_float($value)) { $value = Common::forceDotAsSeparatorForDecimalPoint($value); } $field = $dimension->getColumnName(); if (empty($field)) { $dimensionClass = get_class($dimension); throw new Exception('Dimension ' . $dimensionClass . ' does not define a field name'); } $actionId = $dimension->getActionId(); $actions[$field] = array($value, $actionId); Common::printDebug("$field = $value"); } } $actions = array_filter($actions, 'count'); if (empty($actions)) { return; } $loadedActionIds = TableLogAction::loadIdsAction($actions); $this->actionIdsCached = $loadedActionIds; return $this->actionIdsCached; } /** * Records in the DB the association between the visit and this action. * * @param int $idReferrerActionUrl is the ID of the last action done by the current visit. * @param $idReferrerActionName * @param Visitor $visitor */ public function record(Visitor $visitor, $idReferrerActionUrl, $idReferrerActionName) { $this->loadIdsFromLogActionTable(); $visitAction = array( 'idvisit' => $visitor->getVisitorColumn('idvisit'), 'idsite' => $this->request->getIdSite(), 'idvisitor' => $visitor->getVisitorColumn('idvisitor'), 'idaction_url' => $this->getIdActionUrl(), 'idaction_url_ref' => $idReferrerActionUrl, 'idaction_name_ref' => $idReferrerActionName ); /** @var ActionDimension[] $dimensions */ $dimensions = ActionDimension::getAllDimensions(); foreach ($dimensions as $dimension) { $value = $dimension->onNewAction($this->request, $visitor, $this); if ($value !== false) { if (is_float($value)) { $value = Common::forceDotAsSeparatorForDecimalPoint($value); } $visitAction[$dimension->getColumnName()] = $value; } } // idaction_name is NULLable. we only set it when applicable if ($this->isActionHasActionName()) { $visitAction['idaction_name'] = (int)$this->getIdActionName(); } foreach ($this->actionIdsCached as $field => $idAction) { $visitAction[$field] = ($idAction === false) ? 0 : $idAction; } $customValue = $this->getCustomFloatValue(); if (!empty($customValue)) { $visitAction[self::DB_COLUMN_CUSTOM_FLOAT] = Common::forceDotAsSeparatorForDecimalPoint($customValue); } $customVariables = $this->getCustomVariables(); if (!empty($customVariables)) { Common::printDebug("Page level Custom Variables: "); Common::printDebug($customVariables); } $visitAction = array_merge($visitAction, $customVariables); $this->idLinkVisitAction = $this->getModel()->createAction($visitAction); $visitAction['idlink_va'] = $this->idLinkVisitAction; Common::printDebug("Inserted new action:"); $visitActionDebug = $visitAction; $visitActionDebug['idvisitor'] = bin2hex($visitActionDebug['idvisitor']); Common::printDebug($visitActionDebug); /** * Triggered after successfully persisting a [visit action entity](/guides/persistence-and-the-mysql-backend#visit-actions). * * @param Action $tracker Action The Action tracker instance. * @param array $visitAction The visit action entity that was persisted. Read * [this](/guides/persistence-and-the-mysql-backend#visit-actions) to see what it contains. */ Piwik::postEvent('Tracker.recordAction', array($trackerAction = $this, $visitAction)); } public function writeDebugInfo() { $type = self::getTypeAsString($this->getActionType()); $name = $this->getActionName(); $url = $this->getActionUrl(); Common::printDebug("Action is a $type, Action name = " . $name . ", Action URL = " . $url); return true; } private function getModel() { return new Model(); } /** * @return bool */ private function isActionHasActionName() { $types = array(self::TYPE_PAGE_TITLE, self::TYPE_PAGE_URL, self::TYPE_SITE_SEARCH); return in_array($this->getActionType(), $types); } }