PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/core/Tracker/Action.php

https://github.com/CodeYellowBV/piwik
PHP | 317 lines | 204 code | 50 blank | 63 comment | 15 complexity | d17f2d4b57152724277b76d73931305f MD5 | raw file
Possible License(s): LGPL-3.0, JSON, MIT, GPL-3.0, LGPL-2.1, GPL-2.0, AGPL-1.0, BSD-2-Clause, BSD-3-Clause
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik\Tracker;
  10. use Exception;
  11. use Piwik\Common;
  12. use Piwik\Piwik;
  13. use Piwik\Tracker;
  14. /**
  15. * An action
  16. *
  17. */
  18. abstract class Action
  19. {
  20. const TYPE_PAGE_URL = 1;
  21. const TYPE_OUTLINK = 2;
  22. const TYPE_DOWNLOAD = 3;
  23. const TYPE_PAGE_TITLE = 4;
  24. const TYPE_ECOMMERCE_ITEM_SKU = 5;
  25. const TYPE_ECOMMERCE_ITEM_NAME = 6;
  26. const TYPE_ECOMMERCE_ITEM_CATEGORY = 7;
  27. const TYPE_SITE_SEARCH = 8;
  28. const TYPE_EVENT = 10; // Alias TYPE_EVENT_CATEGORY
  29. const TYPE_EVENT_CATEGORY = 10;
  30. const TYPE_EVENT_ACTION = 11;
  31. const TYPE_EVENT_NAME = 12;
  32. const DB_COLUMN_CUSTOM_FLOAT = 'custom_float';
  33. /**
  34. * Makes the correct Action object based on the request.
  35. *
  36. * @param Request $request
  37. * @return ActionClickUrl|ActionPageview|ActionSiteSearch
  38. */
  39. static public function factory(Request $request)
  40. {
  41. $downloadUrl = $request->getParam('download');
  42. if (!empty($downloadUrl)) {
  43. return new ActionClickUrl(self::TYPE_DOWNLOAD, $downloadUrl, $request);
  44. }
  45. $outlinkUrl = $request->getParam('link');
  46. if (!empty($outlinkUrl)) {
  47. return new ActionClickUrl(self::TYPE_OUTLINK, $outlinkUrl, $request);
  48. }
  49. $url = $request->getParam('url');
  50. $eventCategory = $request->getParam('e_c');
  51. $eventAction = $request->getParam('e_a');
  52. if(strlen($eventCategory) > 0 && strlen($eventAction) > 0 ) {
  53. return new ActionEvent($eventCategory, $eventAction, $url, $request);
  54. }
  55. $action = new ActionSiteSearch($url, $request);
  56. if ($action->isSearchDetected()) {
  57. return $action;
  58. }
  59. return new ActionPageview($url, $request);
  60. }
  61. /**
  62. * @var Request
  63. */
  64. protected $request;
  65. private $idLinkVisitAction;
  66. private $actionIdsCached = array();
  67. private $actionName;
  68. private $actionType;
  69. private $actionUrl;
  70. public function __construct($type, Request $request)
  71. {
  72. $this->actionType = $type;
  73. $this->request = $request;
  74. }
  75. /**
  76. * Returns URL of the page currently being tracked, or the file being downloaded, or the outlink being clicked
  77. *
  78. * @return string
  79. */
  80. public function getActionUrl()
  81. {
  82. return $this->actionUrl;
  83. }
  84. public function getActionName()
  85. {
  86. return $this->actionName;
  87. }
  88. public function getActionType()
  89. {
  90. return $this->actionType;
  91. }
  92. public function getCustomVariables()
  93. {
  94. $customVariables = $this->request->getCustomVariables($scope = 'page');
  95. return $customVariables;
  96. }
  97. // custom_float column
  98. public function getCustomFloatValue()
  99. {
  100. return false;
  101. }
  102. protected function setActionName($name)
  103. {
  104. $name = PageUrl::cleanupString((string)$name);
  105. $this->actionName = $name;
  106. }
  107. protected function setActionUrl($url)
  108. {
  109. $urlBefore = $url;
  110. $url = PageUrl::excludeQueryParametersFromUrl($url, $this->request->getIdSite());
  111. if ($url != $urlBefore) {
  112. Common::printDebug(' Before was "' . $urlBefore . '"');
  113. Common::printDebug(' After is "' . $url . '"');
  114. }
  115. $url = PageUrl::getUrlIfLookValid($url);
  116. $this->actionUrl = $url;
  117. }
  118. abstract protected function getActionsToLookup();
  119. protected function getUrlAndType()
  120. {
  121. $url = $this->getActionUrl();
  122. if (!empty($url)) {
  123. // normalize urls by stripping protocol and www
  124. $url = PageUrl::normalizeUrl($url);
  125. return array($url['url'], Tracker\Action::TYPE_PAGE_URL, $url['prefixId']);
  126. }
  127. return false;
  128. }
  129. public function getIdActionUrl()
  130. {
  131. $idUrl = $this->actionIdsCached['idaction_url'];
  132. // note; idaction_url = 0 is displayed as "Page URL Not Defined"
  133. return (int)$idUrl;
  134. }
  135. public function getIdActionUrlForEntryAndExitIds()
  136. {
  137. return $this->getIdActionUrl();
  138. }
  139. public function getIdActionNameForEntryAndExitIds()
  140. {
  141. return $this->getIdActionName();
  142. }
  143. public function getIdActionName()
  144. {
  145. if(!isset($this->actionIdsCached['idaction_name'])) {
  146. return false;
  147. }
  148. return $this->actionIdsCached['idaction_name'];
  149. }
  150. /**
  151. * Returns the ID of the newly created record in the log_link_visit_action table
  152. *
  153. * @return int
  154. */
  155. public function getIdLinkVisitAction()
  156. {
  157. return $this->idLinkVisitAction;
  158. }
  159. public function writeDebugInfo()
  160. {
  161. $type = self::getTypeAsString($this->getActionType());
  162. Common::printDebug("Action is a $type,
  163. Action name = " . $this->getActionName() . ",
  164. Action URL = " . $this->getActionUrl());
  165. return true;
  166. }
  167. public static function getTypeAsString($type)
  168. {
  169. $class = new \ReflectionClass("\\Piwik\\Tracker\\Action");
  170. $constants = $class->getConstants();
  171. $typeId = array_search($type, $constants);
  172. if($typeId === false) {
  173. throw new Exception("Unexpected action type " . $type);
  174. }
  175. return str_replace('TYPE_', '', $typeId);
  176. }
  177. /**
  178. * Loads the idaction of the current action name and the current action url.
  179. * These idactions are used in the visitor logging table to link the visit information
  180. * (entry action, exit action) to the actions.
  181. * These idactions are also used in the table that links the visits and their actions.
  182. *
  183. * The methods takes care of creating a new record(s) in the action table if the existing
  184. * action name and action url doesn't exist yet.
  185. */
  186. public function loadIdsFromLogActionTable()
  187. {
  188. if(!empty($this->actionIdsCached)) {
  189. return;
  190. }
  191. $actions = $this->getActionsToLookup();
  192. $actions = array_filter($actions, 'count');
  193. if(empty($actions)) {
  194. return;
  195. }
  196. $loadedActionIds = TableLogAction::loadIdsAction($actions);
  197. $this->actionIdsCached = $loadedActionIds;
  198. return $this->actionIdsCached;
  199. }
  200. /**
  201. * Records in the DB the association between the visit and this action.
  202. *
  203. * @param int $idVisit is the ID of the current visit in the DB table log_visit
  204. * @param $visitorIdCookie
  205. * @param int $idReferrerActionUrl is the ID of the last action done by the current visit.
  206. * @param $idReferrerActionName
  207. * @param int $timeSpentReferrerAction is the number of seconds since the last action was done.
  208. * It is directly related to idReferrerActionUrl.
  209. */
  210. public function record($idVisit, $visitorIdCookie, $idReferrerActionUrl, $idReferrerActionName, $timeSpentReferrerAction)
  211. {
  212. $this->loadIdsFromLogActionTable();
  213. $visitAction = array(
  214. 'idvisit' => $idVisit,
  215. 'idsite' => $this->request->getIdSite(),
  216. 'idvisitor' => $visitorIdCookie,
  217. 'server_time' => Tracker::getDatetimeFromTimestamp($this->request->getCurrentTimestamp()),
  218. 'idaction_url' => $this->getIdActionUrl(),
  219. 'idaction_url_ref' => $idReferrerActionUrl,
  220. 'idaction_name_ref' => $idReferrerActionName,
  221. 'time_spent_ref_action' => $timeSpentReferrerAction
  222. );
  223. // idaction_name is NULLable. we only set it when applicable
  224. if($this->isActionHasActionName()) {
  225. $visitAction['idaction_name'] = (int)$this->getIdActionName();
  226. }
  227. foreach($this->actionIdsCached as $field => $idAction) {
  228. $visitAction[$field] = ($idAction === false) ? 0 : $idAction;
  229. }
  230. $customValue = $this->getCustomFloatValue();
  231. if (!empty($customValue)) {
  232. $visitAction[self::DB_COLUMN_CUSTOM_FLOAT] = $customValue;
  233. }
  234. $customVariables = $this->getCustomVariables();
  235. if (!empty($customVariables)) {
  236. Common::printDebug("Page level Custom Variables: ");
  237. Common::printDebug($customVariables);
  238. }
  239. $visitAction = array_merge($visitAction, $customVariables);
  240. $fields = implode(", ", array_keys($visitAction));
  241. $bind = array_values($visitAction);
  242. $values = Common::getSqlStringFieldsArray($visitAction);
  243. $sql = "INSERT INTO " . Common::prefixTable('log_link_visit_action') . " ($fields) VALUES ($values)";
  244. Tracker::getDatabase()->query($sql, $bind);
  245. $this->idLinkVisitAction = Tracker::getDatabase()->lastInsertId();
  246. $visitAction['idlink_va'] = $this->idLinkVisitAction;
  247. Common::printDebug("Inserted new action:");
  248. Common::printDebug($visitAction);
  249. /**
  250. * Triggered after successfully persisting a [visit action entity](/guides/persistence-and-the-mysql-backend#visit-actions).
  251. *
  252. * @param Action $tracker Action The Action tracker instance.
  253. * @param array $visitAction The visit action entity that was persisted. Read
  254. * [this](/guides/persistence-and-the-mysql-backend#visit-actions) to see what it contains.
  255. */
  256. Piwik::postEvent('Tracker.recordAction', array($trackerAction = $this, $visitAction));
  257. }
  258. /**
  259. * @return bool
  260. */
  261. protected function isActionHasActionName()
  262. {
  263. return in_array($this->getActionType(), array(Tracker\Action::TYPE_PAGE_TITLE,
  264. Tracker\Action::TYPE_PAGE_URL,
  265. Tracker\Action::TYPE_SITE_SEARCH));
  266. }
  267. }