Skip to content

Commit

Permalink
Tracking Actions refactoring to accomodate Custom Events matomo-org#472
Browse files Browse the repository at this point in the history
  • Loading branch information
mattab committed Oct 20, 2013
1 parent ed9cd9e commit 099eda0
Show file tree
Hide file tree
Showing 15 changed files with 666 additions and 577 deletions.
586 changes: 111 additions & 475 deletions core/Tracker/Action.php

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions core/Tracker/ActionClickUrl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
* @category Piwik
* @package Piwik
*/

namespace Piwik\Tracker;

use Piwik\Tracker;

/**
* This class represents a download or an outlink.
* This is a particular type of Action: it has no 'name'
*
* @package Piwik\Tracker
*/
class ActionClickUrl extends Action
{
function __construct($type, $url, Request $request)
{
parent::__construct($type, $request);
$this->setActionUrl($url);
}

function getActionNameType()
{
return null;
}

function writeDebugInfo()
{
parent::writeDebugInfo();

if (self::detectActionIsOutlinkOnAliasHost($this, $this->request->getIdSite())) {
Common::printDebug("INFO: The outlink URL host is one of the known host for this website. ");
}
}

/**
* Detect whether action is an outlink given host aliases
*
* @param ActionInterface $action
* @return bool true if the outlink the visitor clicked on points to one of the known hosts for this website
*/
public static function detectActionIsOutlinkOnAliasHost(ActionInterface $action, $idSite)
{
if ($action->getActionType() != ActionInterface::TYPE_OUTLINK) {
return false;
}
$decodedActionUrl = $action->getActionUrl();
$actionUrlParsed = @parse_url($decodedActionUrl);
if (!isset($actionUrlParsed['host'])) {
return false;
}
return Visit::isHostKnownAliasHost($actionUrlParsed['host'], $idSite);
}
}
61 changes: 61 additions & 0 deletions core/Tracker/ActionPageview.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
* @category Piwik
* @package Piwik
*/

namespace Piwik\Tracker;

use Piwik\Tracker;

use Piwik\Config;

class ActionPageview extends Action
{
protected $timeGeneration = false;

function __construct($url, Request $request)
{
parent::__construct(ActionInterface::TYPE_PAGE_URL, $request);

$this->setActionUrl($url);

$actionName = $request->getParam('action_name');
$actionName = $this->cleanupActionName($actionName);
$this->setActionName($actionName);

$this->timeGeneration = $this->request->getPageGenerationTime();
}

function getActionCustomValue()
{
return $this->request->getPageGenerationTime();
}

protected function cleanupActionName($actionName)
{
// get the delimiter, by default '/'; BC, we read the old action_category_delimiter first (see #1067)
$actionCategoryDelimiter = isset(Config::getInstance()->General['action_category_delimiter'])
? Config::getInstance()->General['action_category_delimiter']
: Config::getInstance()->General['action_url_category_delimiter'];

// create an array of the categories delimited by the delimiter
$split = explode($actionCategoryDelimiter, $actionName);

// trim every category
$split = array_map('trim', $split);

// remove empty categories
$split = array_filter($split, 'strlen');

// rebuild the name from the array of cleaned categories
$actionName = implode($actionCategoryDelimiter, $split);
return $actionName;
}

}
249 changes: 249 additions & 0 deletions core/Tracker/ActionSiteSearch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
* @category Piwik
* @package Piwik
*/

namespace Piwik\Tracker;

use Piwik\Common;
use Piwik\Config;
use Piwik\Tracker;
use Piwik\UrlHelper;

class ActionSiteSearch extends Action
{
const CVAR_KEY_SEARCH_CATEGORY = '_pk_scat';
const CVAR_KEY_SEARCH_COUNT = '_pk_scount';
const CVAR_INDEX_SEARCH_CATEGORY = '4';
const CVAR_INDEX_SEARCH_COUNT = '5';
private $searchCategory = false;
private $searchCount = false;

function __construct($url, Request $request)
{
parent::__construct(ActionInterface::TYPE_SITE_SEARCH, $request);
$this->originalUrl = $url;
}

function getActionCustomValue()
{
return $this->request->getPageGenerationTime();
}

function isSearchDetected()
{
$siteSearch = $this->detectSiteSearch($this->originalUrl);

if(empty($siteSearch)) {
return false;
}

list($actionName,$url, $category, $count) = $siteSearch;

if (!empty($category)) {
$this->searchCategory = trim($category);
}
if ($count !== false) {
$this->searchCount = $count;
}
$this->setActionName($actionName);
$this->setActionUrl($url);
}

// FIXMEA replace by getNameAndType
protected function getActionNameType()
{
return ActionInterface::TYPE_SITE_SEARCH;
}

public function getIdActionUrl()
{
// Site Search, by default, will not track URL. We do not want URL to appear as "Page URL not defined"
// so we specifically set it to NULL in the table (the archiving query does IS NOT NULL)
if (empty(Config::getInstance()->Tracker['action_sitesearch_record_url'])) {
return null;
}
return parent::getIdActionUrl();
}

public function getCustomVariables()
{
$customVariables = parent::getCustomVariables();

// Enrich Site Search actions with Custom Variables, overwriting existing values
if (!empty($this->searchCategory)) {
if (!empty($customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_CATEGORY])) {
Common::printDebug("WARNING: Overwriting existing Custom Variable in slot " . self::CVAR_INDEX_SEARCH_CATEGORY . " for this page view");
}
$customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_CATEGORY] = self::CVAR_KEY_SEARCH_CATEGORY;
$customVariables['custom_var_v' . self::CVAR_INDEX_SEARCH_CATEGORY] = Request::truncateCustomVariable($this->searchCategory);
}
if ($this->searchCount !== false) {
if (!empty($customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_COUNT])) {
Common::printDebug("WARNING: Overwriting existing Custom Variable in slot " . self::CVAR_INDEX_SEARCH_COUNT . " for this page view");
}
$customVariables['custom_var_k' . self::CVAR_INDEX_SEARCH_COUNT] = self::CVAR_KEY_SEARCH_COUNT;
$customVariables['custom_var_v' . self::CVAR_INDEX_SEARCH_COUNT] = (int)$this->searchCount;
}
return $customVariables;
}

public function isSiteSearchDetected($originalUrl)
{
return true;
}

protected function detectSiteSearchFromUrl($website, $parsedUrl)
{
$doRemoveSearchParametersFromUrl = false;
$separator = '&';
$count = $actionName = $categoryName = false;

$keywordParameters = isset($website['sitesearch_keyword_parameters'])
? $website['sitesearch_keyword_parameters']
: array();
$queryString = (!empty($parsedUrl['query']) ? $parsedUrl['query'] : '') . (!empty($parsedUrl['fragment']) ? $separator . $parsedUrl['fragment'] : '');
$parametersRaw = UrlHelper::getArrayFromQueryString($queryString);

// strtolower the parameter names for smooth site search detection
$parameters = array();
foreach ($parametersRaw as $k => $v) {
$parameters[Common::mb_strtolower($k)] = $v;
}
// decode values if they were sent from a client using another charset
$pageEncoding = $this->request->getParam('cs');
PageUrl::reencodeParameters($parameters, $pageEncoding);

// Detect Site Search keyword
foreach ($keywordParameters as $keywordParameterRaw) {
$keywordParameter = Common::mb_strtolower($keywordParameterRaw);
if (!empty($parameters[$keywordParameter])) {
$actionName = $parameters[$keywordParameter];
break;
}
}

if (empty($actionName)) {
return false;
}

$categoryParameters = isset($website['sitesearch_category_parameters'])
? $website['sitesearch_category_parameters']
: array();

foreach ($categoryParameters as $categoryParameterRaw) {
$categoryParameter = Common::mb_strtolower($categoryParameterRaw);
if (!empty($parameters[$categoryParameter])) {
$categoryName = $parameters[$categoryParameter];
break;
}
}

if (isset($parameters['search_count'])
&& $this->isValidSearchCount($parameters['search_count'])
) {
$count = $parameters['search_count'];
}
// Remove search kwd from URL
if ($doRemoveSearchParametersFromUrl) {
// @see excludeQueryParametersFromUrl()
// Excluded the detected parameters from the URL
$parametersToExclude = array($categoryParameterRaw, $keywordParameterRaw);
$parsedUrl['query'] = UrlHelper::getQueryStringWithExcludedParameters(UrlHelper::getArrayFromQueryString($parsedUrl['query']), $parametersToExclude);
$parsedUrl['fragment'] = UrlHelper::getQueryStringWithExcludedParameters(UrlHelper::getArrayFromQueryString($parsedUrl['fragment']), $parametersToExclude);
}
$url = UrlHelper::getParseUrlReverse($parsedUrl);
if (is_array($actionName)) {
$actionName = reset($actionName);
}
$actionName = trim(urldecode($actionName));
if (empty($actionName)) {
return false;
}
if (is_array($categoryName)) {
$categoryName = reset($categoryName);
}
$categoryName = trim(urldecode($categoryName));
return array($url, $actionName, $categoryName, $count);
}

protected function isValidSearchCount($count)
{
return is_numeric($count) && $count >= 0;
}

protected function detectSiteSearch($originalUrl)
{
$website = Cache::getCacheWebsiteAttributes($this->request->getIdSite());
if (empty($website['sitesearch'])) {
Common::printDebug("Internal 'Site Search' tracking is not enabled for this site. ");
return false;
}

$actionName = $url = $categoryName = $count = false;
$doTrackUrlForSiteSearch = !empty(Config::getInstance()->Tracker['action_sitesearch_record_url']);

$originalUrl = PageUrl::cleanupUrl($originalUrl);

// Detect Site search from Tracking API parameters rather than URL
$searchKwd = $this->request->getParam('search');
if (!empty($searchKwd)) {
$actionName = $searchKwd;
if ($doTrackUrlForSiteSearch) {
$url = $originalUrl;
}
$isCategoryName = $this->request->getParam('search_cat');
if (!empty($isCategoryName)) {
$categoryName = $isCategoryName;
}
$isCount = $this->request->getParam('search_count');
if ($this->isValidSearchCount($isCount)) {
$count = $isCount;
}
}

if (empty($actionName)) {
$parsedUrl = @parse_url($originalUrl);

// Detect Site Search from URL query parameters
if (!empty($parsedUrl['query']) || !empty($parsedUrl['fragment'])) {
// array($url, $actionName, $categoryName, $count);
$searchInfo = $this->detectSiteSearchFromUrl($website, $parsedUrl);
if (!empty($searchInfo)) {
list ($url, $actionName, $categoryName, $count) = $searchInfo;
}
}
}

if (empty($actionName)) {
Common::printDebug("(this is not a Site Search request)");
return false;
}

Common::printDebug("Detected Site Search keyword '$actionName'. ");
if (!empty($categoryName)) {
Common::printDebug("- Detected Site Search Category '$categoryName'. ");
}
if ($count !== false) {
Common::printDebug("- Search Results Count was '$count'. ");
}
if ($url != $originalUrl) {
Common::printDebug("NOTE: The Page URL was changed / removed, during the Site Search detection, was '$originalUrl', now is '$url'");
}

return array(
$actionName,
$url,
$categoryName,
$count
);
}


}
Loading

0 comments on commit 099eda0

Please sign in to comment.