| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\Tracker; |
|
|
| use Exception; |
| use Piwik\Common; |
| use Piwik\Container\StaticContainer; |
| use Piwik\Plugin\Dimension\ActionDimension; |
| use Piwik\Plugin\Manager; |
| use Piwik\Log\LoggerInterface; |
|
|
| |
| |
| |
| |
| abstract class Action |
| { |
| public const TYPE_PAGE_URL = 1; |
| public const TYPE_OUTLINK = 2; |
| public const TYPE_DOWNLOAD = 3; |
| public const TYPE_PAGE_TITLE = 4; |
| public const TYPE_ECOMMERCE_ITEM_SKU = 5; |
| public const TYPE_ECOMMERCE_ITEM_NAME = 6; |
| public const TYPE_ECOMMERCE_ITEM_CATEGORY = 7; |
| public const TYPE_SITE_SEARCH = 8; |
|
|
| public const TYPE_EVENT = 10; |
| public const TYPE_EVENT_CATEGORY = 10; |
| public const TYPE_EVENT_ACTION = 11; |
| public const TYPE_EVENT_NAME = 12; |
|
|
| public const TYPE_CONTENT = 13; |
| public const TYPE_CONTENT_NAME = 13; |
| public const TYPE_CONTENT_PIECE = 14; |
| public const TYPE_CONTENT_TARGET = 15; |
| public const TYPE_CONTENT_INTERACTION = 16; |
|
|
| public const DB_COLUMN_CUSTOM_FLOAT = 'custom_float'; |
|
|
| private static $factoryPriority = array( |
| self::TYPE_PAGE_URL, |
| self::TYPE_SITE_SEARCH, |
| self::TYPE_CONTENT, |
| self::TYPE_EVENT, |
| self::TYPE_OUTLINK, |
| self::TYPE_DOWNLOAD, |
| ); |
|
|
| |
| |
| |
| |
| |
| public $request; |
|
|
| private $idLinkVisitAction; |
| private $actionIdsCached = array(); |
| private $customFields = array(); |
| private $actionName; |
| private $actionType; |
|
|
| |
| |
| |
| private $actionUrl; |
|
|
| |
| |
| |
| private $rawActionUrl; |
|
|
| |
| |
| |
| private $logger; |
|
|
| |
| |
| |
| |
| |
| public static function factory(Request $request) |
| { |
| |
| $actions = self::getAllActions($request); |
|
|
| foreach ($actions as $actionType) { |
| if (empty($action)) { |
| $action = $actionType; |
| continue; |
| } |
|
|
| $posPrevious = self::getPriority($action); |
| $posCurrent = self::getPriority($actionType); |
|
|
| if ($posCurrent > $posPrevious) { |
| $action = $actionType; |
| } |
| } |
|
|
| if (!empty($action)) { |
| return $action; |
| } |
|
|
| if (self::isCustomActionRequest($request)) { |
| throw new Exception('Request was meant for a plugin which is no longer activated. Request needs to be ignored.'); |
| } |
|
|
| return new ActionPageview($request); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public static function isCustomActionRequest(Request $request) |
| { |
| return $request->hasParam('ca') && $request->getParam('ca'); |
| } |
|
|
| 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) { |
| |
| if ($action::shouldHandle($request)) { |
| $instances[] = new $action($request); |
| } |
| } |
|
|
| return $instances; |
| } |
|
|
| public function __construct($type, Request $request) |
| { |
| $this->actionType = $type; |
| $this->request = $request; |
| $this->logger = StaticContainer::get(LoggerInterface::class); |
| } |
|
|
| |
| |
| |
| |
| |
| public function getActionUrl() |
| { |
| return $this->actionUrl; |
| } |
|
|
| |
| |
| |
| public function getActionUrlRaw() |
| { |
| return $this->rawActionUrl; |
| } |
|
|
| public function getActionName() |
| { |
| return $this->actionName; |
| } |
|
|
| public function getActionType() |
| { |
| return $this->actionType; |
| } |
|
|
| |
| public function getCustomFloatValue() |
| { |
| return false; |
| } |
|
|
| protected function setActionName($name) |
| { |
| $this->actionName = PageUrl::cleanupString((string)$name); |
| } |
|
|
| protected function setActionUrl($url) |
| { |
| $this->rawActionUrl = PageUrl::getUrlIfLookValid($url); |
| $url2 = PageUrl::excludeQueryParametersFromUrl($url, $this->request->getIdSite()); |
|
|
| $this->actionUrl = PageUrl::getUrlIfLookValid($url2); |
|
|
| if ($url != $this->rawActionUrl) { |
| $this->logger->debug(' Before was "{rawActionUrl}"', [ |
| 'rawActionUrl' => $this->rawActionUrl, |
| ]); |
| $this->logger->debug(' After is "{url2}"', [ |
| 'url2' => $url2, |
| ]); |
| } |
| } |
|
|
| 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)) { |
| |
| $url = PageUrl::normalizeUrl($url); |
| return array($url['url'], self::TYPE_PAGE_URL, $url['prefixId']); |
| } |
|
|
| return false; |
| } |
|
|
| public function setCustomField($field, $value) |
| { |
| $this->customFields[$field] = $value; |
| } |
|
|
| public function getCustomField($field) |
| { |
| if (isset($this->customFields[$field])) { |
| return $this->customFields[$field]; |
| } |
| } |
|
|
| public function getCustomFields() |
| { |
| return $this->customFields; |
| } |
|
|
| public function getIdActionUrl() |
| { |
| $idUrl = isset($this->actionIdsCached['idaction_url']) ? $this->actionIdsCached['idaction_url'] : 0; |
| |
| return (int)$idUrl; |
| } |
|
|
| public function getIdActionUrlForEntryAndExitIds() |
| { |
| return false; |
| } |
|
|
| public function getIdActionNameForEntryAndExitIds() |
| { |
| return false; |
| } |
|
|
| public function getIdActionName() |
| { |
| if (!isset($this->actionIdsCached['idaction_name'])) { |
| return false; |
| } |
|
|
| return $this->actionIdsCached['idaction_name']; |
| } |
|
|
| |
| |
| |
| |
| |
| 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) { |
| return $type; |
| } |
|
|
| return str_replace('TYPE_', '', $typeId); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function loadIdsFromLogActionTable() |
| { |
| if (!empty($this->actionIdsCached)) { |
| return; |
| } |
|
|
| |
| $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); |
| $this->logger->debug("$field = $value"); |
| } |
| } |
|
|
| $actions = array_filter($actions); |
|
|
| if (empty($actions)) { |
| return; |
| } |
|
|
| $loadedActionIds = TableLogAction::loadIdsAction($actions); |
|
|
| $this->actionIdsCached = $loadedActionIds; |
| return $this->actionIdsCached; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| 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, |
| ); |
|
|
| |
| $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; |
| } |
| } |
|
|
| |
| 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 ($customValue !== false && $customValue !== null && $customValue !== '') { |
| $visitAction[self::DB_COLUMN_CUSTOM_FLOAT] = Common::forceDotAsSeparatorForDecimalPoint($customValue); |
| } |
|
|
| $visitAction = array_merge($visitAction, $this->customFields); |
|
|
| $this->idLinkVisitAction = $this->getModel()->createAction($visitAction); |
|
|
| $visitAction['idlink_va'] = $this->idLinkVisitAction; |
|
|
| $visitActionDebug = $visitAction; |
| $visitActionDebug['idvisitor'] = bin2hex($visitActionDebug['idvisitor']); |
| $this->logger->debug("Inserted new action: {action}", [ |
| 'action' => var_export($visitActionDebug, true), |
| ]); |
| } |
|
|
| public function writeDebugInfo() |
| { |
| $type = self::getTypeAsString($this->getActionType()); |
| $name = $this->getActionName(); |
| $url = $this->getActionUrl(); |
|
|
| $this->logger->debug('Action is a {type}, Action name = {name}, Action URL = {url}', [ |
| 'type' => $type, |
| 'name' => $name, |
| 'url' => $url, |
| ]); |
|
|
| return true; |
| } |
|
|
| private function getModel() |
| { |
| return new Model(); |
| } |
|
|
| |
| |
| |
| private function isActionHasActionName() |
| { |
| $types = array(self::TYPE_PAGE_TITLE, self::TYPE_PAGE_URL, self::TYPE_SITE_SEARCH); |
|
|
| return in_array($this->getActionType(), $types); |
| } |
| } |
|
|