public function afterRequestProcessed(VisitProperties $visitProperties, Request $request) { $goalsConverted = $request->getMetadata('Goals', 'goalsConverted'); /** @var Action $action */ $action = $request->getMetadata('Actions', 'action'); // if the visit hasn't already been converted another way (ie, manual goal conversion or ecommerce conversion, // try to convert based on the action) if (empty($goalsConverted) && $action) { $goalsConverted = $this->goalManager->detectGoalsMatchingUrl($request->getIdSite(), $action); $existingGoalsConverted = $request->getMetadata('Goals', 'goalsConverted') ?: array(); $request->setMetadata('Goals', 'goalsConverted', array_merge($existingGoalsConverted, $goalsConverted)); if (!empty($goalsConverted)) { $request->setMetadata('Goals', 'visitIsConverted', true); } } // There is an edge case when: // - two manual goal conversions happen in the same second // - which result in handleExistingVisit throwing the exception // because the UPDATE didn't affect any rows (one row was found, but not updated since no field changed) // - the exception is caught here and will result in a new visit incorrectly // In this case, we cancel the current conversion to be recorded: $isManualGoalConversion = $this->isManualGoalConversion($request); $requestIsEcommerce = $request->getMetadata('Goals', 'isRequestEcommerce'); $visitorNotFoundInDb = $request->getMetadata('CoreHome', 'visitorNotFoundInDb'); if ($visitorNotFoundInDb && ($isManualGoalConversion || $requestIsEcommerce)) { $request->setMetadata('Goals', 'goalsConverted', array()); $request->setMetadata('Goals', 'visitIsConverted', false); } }
/** * Main algorithm to handle the visit. * * Once we have the visitor information, we have to determine if the visit is a new or a known visit. * * 1) When the last action was done more than 30min ago, * or if the visitor is new, then this is a new visit. * * 2) If the last action is less than 30min ago, then the same visit is going on. * Because the visit goes on, we can get the time spent during the last action. * * NB: * - In the case of a new visit, then the time spent * during the last action of the previous visit is unknown. * * - In the case of a new visit but with a known visitor, * we can set the 'returning visitor' flag. * * In all the cases we set a cookie to the visitor with the new information. */ public function handle() { foreach ($this->requestProcessors as $processor) { Common::printDebug("Executing " . get_class($processor) . "::manipulateRequest()..."); $processor->manipulateRequest($this->request); } $this->visitProperties = new VisitProperties(); foreach ($this->requestProcessors as $processor) { Common::printDebug("Executing " . get_class($processor) . "::processRequestParams()..."); $abort = $processor->processRequestParams($this->visitProperties, $this->request); if ($abort) { Common::printDebug("-> aborting due to processRequestParams method"); return; } } $isNewVisit = $this->request->getMetadata('CoreHome', 'isNewVisit'); if (!$isNewVisit) { $isNewVisit = $this->triggerPredicateHookOnDimensions($this->getAllVisitDimensions(), 'shouldForceNewVisit'); $this->request->setMetadata('CoreHome', 'isNewVisit', $isNewVisit); } foreach ($this->requestProcessors as $processor) { Common::printDebug("Executing " . get_class($processor) . "::afterRequestProcessed()..."); $abort = $processor->afterRequestProcessed($this->visitProperties, $this->request); if ($abort) { Common::printDebug("-> aborting due to afterRequestProcessed method"); return; } } $isNewVisit = $this->request->getMetadata('CoreHome', 'isNewVisit'); // Known visit when: // ( - the visitor has the Piwik cookie with the idcookie ID used by Piwik to match the visitor // OR // - the visitor doesn't have the Piwik cookie but could be match using heuristics @see recognizeTheVisitor() // ) // AND // - the last page view for this visitor was less than 30 minutes ago @see isLastActionInTheSameVisit() if (!$isNewVisit) { try { $this->handleExistingVisit($this->request->getMetadata('Goals', 'visitIsConverted')); } catch (VisitorNotFoundInDb $e) { $this->request->setMetadata('CoreHome', 'visitorNotFoundInDb', true); // TODO: perhaps we should just abort here? } } // New visit when: // - the visitor has the Piwik cookie but the last action was performed more than 30 min ago @see isLastActionInTheSameVisit() // - the visitor doesn't have the Piwik cookie, and couldn't be matched in @see recognizeTheVisitor() // - the visitor does have the Piwik cookie but the idcookie and idvisit found in the cookie didn't match to any existing visit in the DB if ($isNewVisit) { $this->handleNewVisit($this->request->getMetadata('Goals', 'visitIsConverted')); } // update the cookie with the new visit information $this->request->setThirdPartyCookie($this->visitProperties->getProperty('idvisitor')); foreach ($this->requestProcessors as $processor) { Common::printDebug("Executing " . get_class($processor) . "::recordLogs()..."); $processor->recordLogs($this->visitProperties, $this->request); } $this->markArchivedReportsAsInvalidIfArchiveAlreadyFinished(); }
public function afterRequestProcessed(VisitProperties $visitProperties, Request $request) { $goalsConverted = $request->getMetadata('Goals', 'goalsConverted'); if (!empty($goalsConverted)) { $isThereExistingCartInVisit = $this->goalManager->detectIsThereExistingCartInVisit($visitProperties->getProperties()); $request->setMetadata('Goals', 'isThereExistingCartInVisit', $isThereExistingCartInVisit); } }
/** * @param Request $request * @param Visitor $visitor * @param Action|null $action * @return int */ public function onExistingVisit(Request $request, Visitor $visitor, $action) { $request->setMetadata('Actions', $this->columnName, $visitor->getVisitorColumn($this->columnName)); if (self::shouldCountInteraction($action)) { return $this->columnName . ' + 1'; } return false; }
public function processRequestParams(VisitProperties $visitProperties, Request $request) { // TODO: re-add optimization where if custom variables exist in request, don't bother selecting them in Visitor $visitorCustomVariables = $request->getCustomVariables($scope = 'visit'); if (!empty($visitorCustomVariables)) { Common::printDebug("Visit level Custom Variables: "); Common::printDebug($visitorCustomVariables); } $request->setMetadata('CustomVariables', 'visitCustomVariables', $visitorCustomVariables); }
public function test_extract_withAction_shouldReadValueFromAction_NotFromPassedRequest() { $request = $this->buildRequest(); $action = new ActionPageview($request); // we create a new empty request here to make sure it actually reads the value from $action and not from $request $request = new Request(array()); $request->setMetadata('Actions', 'action', $action); $value = $this->buildExtraction('urlparam', 'module')->extract($request); $this->assertSame('CoreHome', $value); $value = $this->buildExtraction('action_name', 'My(.+)Title')->extract($request); $this->assertSame(' Test ', $value); }
public function test_afterRequestProcessed_NoActionSet_ShouldBeAbleToHandleCaseSensitive() { $configuration = new Configuration(); $extractions = array(array('dimension' => 'url', 'pattern' => 'wwW(.+).com')); $configuration->configureNewDimension($idSite = 1, 'MyName1', CustomDimensions::SCOPE_ACTION, 1, true, $extractions, $caseSensitive = true); $configuration->configureNewDimension($idSite = 1, 'MyName2', CustomDimensions::SCOPE_ACTION, 2, true, $extractions, $caseSensitive = false); $request = new Request(array('idsite' => 1, 'url' => 'http://www.exAmple.com/test?id=11&module=test')); $action = new ActionPageview($request); $request->setMetadata('Actions', 'action', $action); $this->processor->afterRequestProcessed(new VisitProperties(), $request); $this->assertSame(array('custom_dimension_2' => '.exAmple'), $action->getCustomFields()); }