Skip to content
Extraits de code Groupes Projets
Valider 45c929d8 rédigé par diosmosis's avatar diosmosis
Parcourir les fichiers

Allow Segments to define multiple SQL columns if the segment value can be...

Allow Segments to define multiple SQL columns if the segment value can be matched in any of those fields, and use to define two new segments: customVariableName & customVariableValue.
parent f674f696
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Affichage de
avec 213 ajouts et 31 suppressions
......@@ -145,7 +145,7 @@ class SegmentExpression
$operand = $this->getSqlMatchFromDefinition($operandDefinition, $availableTables);
if ($operand[1] !== null) {
$this->valuesBind[] = $operand[1];
$this->valuesBind = array_merge($this->valuesBind, $operand[1]);
}
$operand = $operand[0];
......@@ -172,12 +172,12 @@ class SegmentExpression
*/
protected function getSqlMatchFromDefinition($def, &$availableTables)
{
$field = $def[0];
$fields = $def[0];
$matchType = $def[1];
$value = $def[2];
// Segment::getCleanedExpression() may return array(null, $matchType, null)
$operandWillNotMatchAnyRow = is_null($field) && is_null($value);
$operandWillNotMatchAnyRow = empty($fields) && is_null($value);
if($operandWillNotMatchAnyRow) {
if($matchType == self::MATCH_EQUAL) {
// eg. pageUrl==DoesNotExist
......@@ -196,44 +196,48 @@ class SegmentExpression
return array($sqlExpression, $value = null);
}
if (!is_array($fields)) {
$fields = array($fields);
}
$alsoMatchNULLValues = false;
switch ($matchType) {
case self::MATCH_EQUAL:
$sqlMatch = '=';
$sqlMatch = '%s =';
break;
case self::MATCH_NOT_EQUAL:
$sqlMatch = '<>';
$sqlMatch = '%s <>';
$alsoMatchNULLValues = true;
break;
case self::MATCH_GREATER:
$sqlMatch = '>';
$sqlMatch = '%s >';
break;
case self::MATCH_LESS:
$sqlMatch = '<';
$sqlMatch = '%s <';
break;
case self::MATCH_GREATER_OR_EQUAL:
$sqlMatch = '>=';
$sqlMatch = '%s >=';
break;
case self::MATCH_LESS_OR_EQUAL:
$sqlMatch = '<=';
$sqlMatch = '%s <=';
break;
case self::MATCH_CONTAINS:
$sqlMatch = 'LIKE';
$sqlMatch = '%s LIKE';
$value = '%' . $this->escapeLikeString($value) . '%';
break;
case self::MATCH_DOES_NOT_CONTAIN:
$sqlMatch = 'NOT LIKE';
$sqlMatch = '%s NOT LIKE';
$value = '%' . $this->escapeLikeString($value) . '%';
$alsoMatchNULLValues = true;
break;
case self::MATCH_IS_NOT_NULL_NOR_EMPTY:
$sqlMatch = 'IS NOT NULL AND (' . $field . ' <> \'\' OR ' . $field . ' = 0)';
$sqlMatch = '%s IS NOT NULL AND (%s <> \'\' OR %s = 0)';
$value = null;
break;
case self::MATCH_IS_NULL_OR_EMPTY:
$sqlMatch = 'IS NULL OR ' . $field . ' = \'\' ';
$sqlMatch = '%s IS NULL OR %s = \'\' ';
$value = null;
break;
......@@ -242,7 +246,7 @@ class SegmentExpression
// (it won't be matched in self::parseSubExpressions())
// it can be used internally to inject sub-expressions into the query.
// see Segment::getCleanedExpression()
$sqlMatch = 'IN (' . $value['SQL'] . ')';
$sqlMatch = '%s IN (' . $value['SQL'] . ')';
$value = $this->escapeLikeString($value['bind']);
break;
default:
......@@ -253,21 +257,38 @@ class SegmentExpression
// We match NULL values when rows are excluded only when we are not doing a
$alsoMatchNULLValues = $alsoMatchNULLValues && !empty($value);
if ($matchType === self::MATCH_ACTIONS_CONTAINS
|| is_null($value)
) {
$sqlExpression = "( $field $sqlMatch )";
} else {
if ($alsoMatchNULLValues) {
$sqlExpression = "( $field IS NULL OR $field $sqlMatch ? )";
$sqlExpressions = array();
$values = array();
foreach ($fields as $field) {
$sqlMatchReplaced = str_replace('%s', $field, $sqlMatch);
if ($matchType === self::MATCH_ACTIONS_CONTAINS
|| is_null($value)
) {
$sqlExpression = "( $sqlMatchReplaced )";
} else {
$sqlExpression = "$field $sqlMatch ?";
if ($alsoMatchNULLValues) {
$sqlExpression = "( $field IS NULL OR $sqlMatchReplaced ? )";
} else {
$sqlExpression = "$sqlMatchReplaced ?";
}
}
$sqlExpressions[] = $sqlExpression;
if ($value !== null) {
$values[] = $value;
}
$this->checkFieldIsAvailable($field, $availableTables);
}
$this->checkFieldIsAvailable($field, $availableTables);
if (count($fields) == 1) {
$sqlExpression = reset($sqlExpressions);
} else {
$sqlExpression = '((' . implode(") OR (", $sqlExpressions) . '))';
}
return array($sqlExpression, $value);
return array($sqlExpression, $values);
}
/**
......
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\CustomVariables\Columns;
use Piwik\Piwik;
use Piwik\Plugin\Dimension\VisitDimension;
use Piwik\Plugin\Segment;
use Piwik\Plugins\CustomVariables\CustomVariables;
class Base extends VisitDimension
{
protected function configureSegmentsFor($fieldPrefix, $segmentNameSuffix)
{
$numCustomVariables = CustomVariables::getNumUsableCustomVariables();
$segment = new Segment();
$segment->setType('dimension');
$segment->setSegment('customVariable' . $segmentNameSuffix);
$segment->setName($this->getName());
$segment->setCategory('CustomVariables_CustomVariables');
$segment->setSqlSegment($this->getSegmentColumns('log_visit.' . $fieldPrefix, $numCustomVariables));
$this->addSegment($segment);
$segment = new Segment();
$segment->setType('dimension');
$segment->setSegment('customVariablePage' . $segmentNameSuffix);
$segment->setName($this->getName() . ' (' . Piwik::translate('CustomVariables_ScopePage') . ')');
$segment->setCategory('CustomVariables_CustomVariables');
$segment->setSqlSegment($this->getSegmentColumns('log_link_visit_action.' . $fieldPrefix, $numCustomVariables));
$this->addSegment($segment);
}
private function getSegmentColumns($column, $numCustomVariables)
{
$columns = array();
for ($i = 1; $i <= $numCustomVariables; ++$i) {
$columns[] = $column . $i;
}
return $columns;
}
}
\ No newline at end of file
......@@ -9,10 +9,14 @@
namespace Piwik\Plugins\CustomVariables\Columns;
use Piwik\Piwik;
use Piwik\Plugin\Dimension\VisitDimension;
class CustomVariableName extends VisitDimension
class CustomVariableName extends Base
{
protected function configureSegments()
{
$this->configureSegmentsFor('custom_var_k', 'Name');
}
public function getName()
{
return Piwik::translate('CustomVariables_ColumnCustomVariableName');
......
......@@ -9,10 +9,14 @@
namespace Piwik\Plugins\CustomVariables\Columns;
use Piwik\Piwik;
use Piwik\Plugin\Dimension\VisitDimension;
class CustomVariableValue extends VisitDimension
class CustomVariableValue extends Base
{
protected function configureSegments()
{
$this->configureSegmentsFor('custom_var_v', 'Value');
}
public function getName()
{
return Piwik::translate('CustomVariables_ColumnCustomVariableValue');
......
......@@ -43,8 +43,8 @@ class CustomVariablesSystemTest extends SystemTestCase
array($apiToCall, array(
'idSite' => self::$fixture->idSite,
'date' => self::$fixture->dateTime,
'periods' => array('day'))
)
'periods' => array('day'),
)),
);
}
......
......@@ -15,6 +15,7 @@
<url>http://localhost</url>
<icon>plugins/Morpheus/images/goal.png</icon>
</row>
<row>
<type>action</type>
......@@ -58,6 +59,7 @@
</row>
</customVariables>
<icon />
</row>
</actionDetails>
<goalConversions>1</goalConversions>
......
......@@ -80,7 +80,7 @@ class TwoVisitsWithCustomVariables extends Fixture
// At first, visitor custom var is set to LoggedOut
$visitorA->setForceVisitDateTime(Date::factory($dateTime)->addHour(0.1)->getDatetime());
$visitorA->setUrl('http://example.org/homepage');
$visitorA->setCustomVariable($id = 1, $name = 'VisitorType', $value = 'LoggedOut');
$visitorA->setCustomVariable($id = 2, $name = 'VisitorType', $value = 'LoggedOut');
self::checkResponse($visitorA->doTrackPageView('Homepage'));
self::checkResponse($visitorA->doTrackGoal($idGoal2));
......
......@@ -92,6 +92,15 @@ class SegmentTest extends IntegrationTestCase
'bind' => array('ff')
)),
// test multiple column segments
array('customVariableName==abc;customVariableValue==def', array(
'where' => ' ((log_visit.custom_var_k1 = ?) OR (log_visit.custom_var_k2 = ?) OR (log_visit.custom_var_k3 = ?) OR (log_visit.custom_var_k4 = ?) OR (log_visit.custom_var_k5 = ?))'
. ' AND ((log_visit.custom_var_v1 = ?) OR (log_visit.custom_var_v2 = ?) OR (log_visit.custom_var_v3 = ?) OR (log_visit.custom_var_v4 = ?) OR (log_visit.custom_var_v5 = ?)) ',
'bind' => array(
'abc', 'abc', 'abc', 'abc', 'abc',
'def', 'def', 'def', 'def', 'def',
),
)),
);
}
......
......@@ -18,6 +18,9 @@ use Piwik\Tests\Fixtures\TwoVisitsWithCustomVariables;
*/
class TwoVisitsWithCustomVariablesTest extends SystemTestCase
{
/**
* @var TwoVisitsWithCustomVariables
*/
public static $fixture = null; // initialized below class definition
public function getApiForTesting()
......@@ -41,6 +44,32 @@ class TwoVisitsWithCustomVariablesTest extends SystemTestCase
'apiAction' => 'getCustomVariablesValuesFromNameId',
'supertableApi' => 'CustomVariables.getCustomVariables',
'testSuffix' => '__subtable')),
// test w/ custom variable segments
array('VisitsSummary.get', array(
'idSite' => self::$fixture->idSite,
'date' => self::$fixture->dateTime,
'periods' => array('day'),
'testSuffix' => '_segmentCustomVarName',
'segment' => 'customVariablePageName=@SET WITH',
)),
array('VisitsSummary.get', array(
'idSite' => self::$fixture->idSite,
'date' => self::$fixture->dateTime,
'periods' => array('day'),
'testSuffix' => '_segmentCustomVarValue',
'segment' => 'customVariableValue=@LoggedIn',
)),
array('VisitsSummary.get', array(
'idSite' => self::$fixture->idSite,
'date' => self::$fixture->dateTime,
'periods' => array('day'),
'testSuffix' => '_segmentAll',
'segment' => 'customVariableName=@Othercustom,customVariablePageValue=@abcdefghi',
)),
);
return $return;
......
......@@ -276,6 +276,12 @@
<name>Event Name</name>
<segment>eventName</segment>
</row>
<row>
<type>dimension</type>
<category>Custom Variables</category>
<name>Custom Variable name</name>
<segment>customVariableName</segment>
</row>
<row>
<type>dimension</type>
<category>Custom Variables</category>
......@@ -306,6 +312,12 @@
<name>Custom Variable name 5 (scope visit)</name>
<segment>customVariableName5</segment>
</row>
<row>
<type>dimension</type>
<category>Custom Variables</category>
<name>Custom Variable name (scope page)</name>
<segment>customVariablePageName</segment>
</row>
<row>
<type>dimension</type>
<category>Custom Variables</category>
......@@ -336,6 +348,12 @@
<name>Custom Variable name 5 (scope page)</name>
<segment>customVariablePageName5</segment>
</row>
<row>
<type>dimension</type>
<category>Custom Variables</category>
<name>Custom Variable value (scope page)</name>
<segment>customVariablePageValue</segment>
</row>
<row>
<type>dimension</type>
<category>Custom Variables</category>
......@@ -366,6 +384,12 @@
<name>Custom Variable value 5 (scope page)</name>
<segment>customVariablePageValue5</segment>
</row>
<row>
<type>dimension</type>
<category>Custom Variables</category>
<name>Custom Variable value</name>
<segment>customVariableValue</segment>
</row>
<row>
<type>dimension</type>
<category>Custom Variables</category>
......
<?xml version="1.0" encoding="utf-8" ?>
<result>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_users>0</nb_users>
<nb_visits>2</nb_visits>
<nb_actions>2</nb_actions>
<nb_visits_converted>1</nb_visits_converted>
<bounce_count>2</bounce_count>
<sum_visit_length>361</sum_visit_length>
<max_actions>1</max_actions>
<bounce_rate>100%</bounce_rate>
<nb_actions_per_visit>1</nb_actions_per_visit>
<avg_time_on_site>181</avg_time_on_site>
</result>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8" ?>
<result>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_users>0</nb_users>
<nb_visits>1</nb_visits>
<nb_actions>4</nb_actions>
<nb_visits_converted>1</nb_visits_converted>
<bounce_count>0</bounce_count>
<sum_visit_length>361</sum_visit_length>
<max_actions>4</max_actions>
<bounce_rate>0%</bounce_rate>
<nb_actions_per_visit>4</nb_actions_per_visit>
<avg_time_on_site>361</avg_time_on_site>
</result>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8" ?>
<result>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_users>0</nb_users>
<nb_visits>1</nb_visits>
<nb_actions>4</nb_actions>
<nb_visits_converted>1</nb_visits_converted>
<bounce_count>0</bounce_count>
<sum_visit_length>361</sum_visit_length>
<max_actions>4</max_actions>
<bounce_rate>0%</bounce_rate>
<nb_actions_per_visit>4</nb_actions_per_visit>
<avg_time_on_site>361</avg_time_on_site>
</result>
\ No newline at end of file
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter