Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Steur <thomas.steur@gmail.com>2015-11-04 05:30:26 +0300
committerThomas Steur <thomas.steur@gmail.com>2015-11-24 04:04:01 +0300
commitd995029b91f38bd81fbbb50f4d058f3b6b3c18a2 (patch)
tree3ba63b979bde2da095ddb06bb66fe92b2d72c31b /plugins/SegmentEditor
parentf9c851190ed680eb430d9d52040b72c7cf73f62a (diff)
refs #9129 added feature Custom Dimensions
Diffstat (limited to 'plugins/SegmentEditor')
-rw-r--r--plugins/SegmentEditor/SegmentEditor.php6
-rw-r--r--plugins/SegmentEditor/SegmentFormatter.php142
-rw-r--r--plugins/SegmentEditor/SegmentList.php32
-rw-r--r--plugins/SegmentEditor/SegmentSelectorControl.php5
-rw-r--r--plugins/SegmentEditor/javascripts/Segmentation.js2
-rw-r--r--plugins/SegmentEditor/lang/en.json7
-rw-r--r--plugins/SegmentEditor/templates/_segmentSelector.twig2
-rw-r--r--plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php110
-rw-r--r--plugins/SegmentEditor/tests/Integration/SegmentListTest.php74
9 files changed, 376 insertions, 4 deletions
diff --git a/plugins/SegmentEditor/SegmentEditor.php b/plugins/SegmentEditor/SegmentEditor.php
index 9107935e73..a46be068bc 100644
--- a/plugins/SegmentEditor/SegmentEditor.php
+++ b/plugins/SegmentEditor/SegmentEditor.php
@@ -28,6 +28,7 @@ class SegmentEditor extends \Piwik\Plugin
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'Template.nextToCalendar' => 'getSegmentEditorHtml',
+ 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
);
}
@@ -85,4 +86,9 @@ class SegmentEditor extends \Piwik\Plugin
{
return Config::getInstance()->General['allow_adding_segments_for_all_websites'] == 1;
}
+
+ public function getClientSideTranslationKeys(&$translationKeys)
+ {
+ $translationKeys[] = 'SegmentEditor_CustomSegment';
+ }
}
diff --git a/plugins/SegmentEditor/SegmentFormatter.php b/plugins/SegmentEditor/SegmentFormatter.php
new file mode 100644
index 0000000000..54dcc20c99
--- /dev/null
+++ b/plugins/SegmentEditor/SegmentFormatter.php
@@ -0,0 +1,142 @@
+<?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\SegmentEditor;
+
+use Exception;
+use Piwik\Config;
+use Piwik\Db;
+use Piwik\Piwik;
+use Piwik\Segment;
+use Piwik\Segment\SegmentExpression;
+
+/**
+ */
+class SegmentFormatter
+{
+ /**
+ * @var SegmentList
+ */
+ private $segmentList;
+
+ private $matchesMetric = array(
+ SegmentExpression::MATCH_EQUAL => 'General_OperationEquals',
+ SegmentExpression::MATCH_NOT_EQUAL => 'General_OperationNotEquals',
+ SegmentExpression::MATCH_LESS_OR_EQUAL => 'General_OperationAtMost',
+ SegmentExpression::MATCH_GREATER_OR_EQUAL => 'General_OperationAtLeast',
+ SegmentExpression::MATCH_LESS => 'General_OperationLessThan',
+ SegmentExpression::MATCH_GREATER => 'General_OperationGreaterThan',
+ );
+
+ private $matchesDimension = array(
+ SegmentExpression::MATCH_EQUAL => 'General_OperationIs',
+ SegmentExpression::MATCH_NOT_EQUAL => 'General_OperationIsNot',
+ SegmentExpression::MATCH_CONTAINS => 'General_OperationContains',
+ SegmentExpression::MATCH_DOES_NOT_CONTAIN => 'General_OperationDoesNotContain',
+ SegmentExpression::MATCH_STARTS_WITH => 'General_OperationStartsWith',
+ SegmentExpression::MATCH_ENDS_WITH => 'General_OperationEndsWith'
+ );
+
+ private $operators = array(
+ SegmentExpression::BOOL_OPERATOR_AND => 'General_And',
+ SegmentExpression::BOOL_OPERATOR_OR => 'General_Or',
+ SegmentExpression::BOOL_OPERATOR_END => '',
+ );
+
+ public function __construct(SegmentList $segmentList)
+ {
+ $this->segmentList = $segmentList;
+ }
+
+ public function getHumanReadable($segmentString, $idSite)
+ {
+ if (empty($segmentString)) {
+ return Piwik::translate('SegmentEditor_DefaultAllVisits');
+ }
+
+ $segment = new SegmentExpression($segmentString);
+ $expressions = $segment->parseSubExpressions();
+
+ $readable = '';
+ foreach ($expressions as $expression) {
+ $operator = $expression[SegmentExpression::INDEX_BOOL_OPERATOR];
+ $operand = $expression[SegmentExpression::INDEX_OPERAND];
+ $name = $operand[SegmentExpression::INDEX_OPERAND_NAME];
+
+ $segment = $this->segmentList->findSegment($name, $idSite);
+
+ if (empty($segment)) {
+ throw new Exception(sprintf("The segment '%s' does not exist.", $name));
+ }
+
+ $readable .= $segment['name'] . ' ';
+ $readable .= $this->getTranslationForComparison($operand, $segment['type']) . ' ';
+ $readable .= $this->getFormattedValue($operand);
+ $readable .= $this->getTranslationForBoolOperator($operator) . ' ';
+ }
+
+ $readable = trim($readable);
+
+ return $readable;
+ }
+
+ private function getTranslationForComparison($operand, $segmentType)
+ {
+ $operator = $operand[SegmentExpression::INDEX_OPERAND_OPERATOR];
+
+ $translation = $operator;
+
+ if ($operator === SegmentExpression::MATCH_IS_NULL_OR_EMPTY) {
+ return Piwik::translate('SegmentEditor_SegmentOperatorIsNullOrEmpty');
+ }
+
+ if ($operator === SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY) {
+ return Piwik::translate('SegmentEditor_SegmentOperatorIsNotNullNorEmpty');
+ }
+
+ if ($segmentType === 'dimension' && !empty($this->matchesDimension[$operator])) {
+ $translation = Piwik::translate($this->matchesDimension[$operator]);
+ }
+ if ($segmentType === 'metric' && !empty($this->matchesMetric[$operator])) {
+ $translation = Piwik::translate($this->matchesMetric[$operator]);
+ }
+
+ return strtolower($translation);
+ }
+
+ private function getFormattedValue($operand)
+ {
+ $operator = $operand[SegmentExpression::INDEX_OPERAND_OPERATOR];
+
+ if ($operator === SegmentExpression::MATCH_IS_NULL_OR_EMPTY
+ || $operator === SegmentExpression::MATCH_IS_NOT_NULL_NOR_EMPTY) {
+ return '';
+ }
+
+ $value = $operand[SegmentExpression::INDEX_OPERAND_VALUE];
+
+ if (empty($value)) {
+ $value = '';
+ }
+
+ return '"' . $value . '" ';
+ }
+
+ private function getTranslationForBoolOperator($operator)
+ {
+ $translation = '';
+
+ if (!empty($this->operators[$operator])) {
+ $translation = Piwik::translate($this->operators[$operator]);
+ } elseif (!empty($operator)) {
+ $translation = $operator;
+ }
+
+ return $translation;
+ }
+}
diff --git a/plugins/SegmentEditor/SegmentList.php b/plugins/SegmentEditor/SegmentList.php
new file mode 100644
index 0000000000..e7094d4793
--- /dev/null
+++ b/plugins/SegmentEditor/SegmentList.php
@@ -0,0 +1,32 @@
+<?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\SegmentEditor;
+
+use Piwik\API\Request;
+use Piwik\Config;
+use Piwik\Db;
+
+/**
+ */
+class SegmentList
+{
+ public function findSegment($segmentName, $idSite)
+ {
+ $segments = Request::processRequest('API.getSegmentsMetadata', array(
+ 'idSites' => array($idSite),
+ ));
+
+ foreach ($segments as $segment) {
+ if ($segment['segment'] == $segmentName && !empty($segmentName)) {
+ return $segment;
+ }
+ }
+ }
+
+}
diff --git a/plugins/SegmentEditor/SegmentSelectorControl.php b/plugins/SegmentEditor/SegmentSelectorControl.php
index 9dc2659660..b01018dbcf 100644
--- a/plugins/SegmentEditor/SegmentSelectorControl.php
+++ b/plugins/SegmentEditor/SegmentSelectorControl.php
@@ -8,8 +8,10 @@
*/
namespace Piwik\Plugins\SegmentEditor;
+use Piwik\API\Request;
use Piwik\Common;
use Piwik\Config;
+use Piwik\Container\StaticContainer;
use Piwik\Piwik;
use Piwik\Plugins\API\API as APIMetadata;
use Piwik\View\UIControl;
@@ -37,6 +39,9 @@ class SegmentSelectorControl extends UIControl
$this->selectedSegment = Common::getRequestVar('segment', false, 'string');
+ $formatter = StaticContainer::get('Piwik\Plugins\SegmentEditor\SegmentFormatter');
+ $this->segmentDescription = $formatter->getHumanReadable(Request::getRawSegmentFromRequest(), $this->idSite);
+
$this->isAddingSegmentsForAllWebsitesEnabled = SegmentEditor::isAddingSegmentsForAllWebsitesEnabled();
$segments = APIMetadata::getInstance()->getSegmentsMetadata($this->idSite);
diff --git a/plugins/SegmentEditor/javascripts/Segmentation.js b/plugins/SegmentEditor/javascripts/Segmentation.js
index ec1e8f23b8..2ffd7dac57 100644
--- a/plugins/SegmentEditor/javascripts/Segmentation.js
+++ b/plugins/SegmentEditor/javascripts/Segmentation.js
@@ -85,7 +85,7 @@ Segmentation = (function($) {
var name = $(foundItems).first().find("span.segname").text();
title.text(name);
} else {
- title.text("Custom Segment");
+ title.text(_pk_translate('SegmentEditor_CustomSegment'));
}
segmentationTitle.html(title);
}
diff --git a/plugins/SegmentEditor/lang/en.json b/plugins/SegmentEditor/lang/en.json
index 933ac73884..a9ba4382e0 100644
--- a/plugins/SegmentEditor/lang/en.json
+++ b/plugins/SegmentEditor/lang/en.json
@@ -6,7 +6,7 @@
"AreYouSureDeleteSegment": "Are you sure you want to delete this segment?",
"AutoArchivePreProcessed": "segmented reports are pre-processed (faster, requires cron)",
"AutoArchiveRealTime": "segmented reports are processed in real time",
- "ChooseASegment": "Choose a segment",
+ "ChooseASegment": "Choose a segment, currently selected segment: %s",
"DataAvailableAtLaterDate": "Your segmented analytics reports will be available later. We apologize for the inconvenience.",
"DefaultAllVisits": "All visits",
"DragDropCondition": "Drag & Drop condition",
@@ -27,6 +27,9 @@
"YouMustBeLoggedInToCreateSegments": "You must be logged in to create and edit custom visitor segments.",
"YouDontHaveAccessToCreateSegments": "You don't have the required access level to create and edit segments.",
"AddingSegmentForAllWebsitesDisabled": "Adding segments for all websites has been disabled.",
- "SegmentXIsAUnionOf": "%s is a union of these segments:"
+ "SegmentXIsAUnionOf": "%s is a union of these segments:",
+ "CustomSegment": "Custom Segment",
+ "SegmentOperatorIsNullOrEmpty": "is null or empty",
+ "SegmentOperatorIsNotNullNorEmpty": "is not null nor empty"
}
} \ No newline at end of file
diff --git a/plugins/SegmentEditor/templates/_segmentSelector.twig b/plugins/SegmentEditor/templates/_segmentSelector.twig
index f2d53b60c7..c14921a046 100644
--- a/plugins/SegmentEditor/templates/_segmentSelector.twig
+++ b/plugins/SegmentEditor/templates/_segmentSelector.twig
@@ -1,5 +1,5 @@
<div class="SegmentEditor" style="display:none;">
- <div class="segmentationContainer listHtml" title="{{ 'SegmentEditor_ChooseASegment'|translate|e('html_attr') }}">
+ <div class="segmentationContainer listHtml" title="{{ 'SegmentEditor_ChooseASegment'|translate(segmentDescription)|e('html_attr') }}">
<a class="title"><span class="icon icon-segment"></span><span class="segmentationTitle"></span></a>
<div class="dropdown dropdown-body">
<div class="segmentFilterContainer">
diff --git a/plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php b/plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php
new file mode 100644
index 0000000000..bc0f206784
--- /dev/null
+++ b/plugins/SegmentEditor/tests/Integration/SegmentFormatterTest.php
@@ -0,0 +1,110 @@
+<?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\SegmentEditor\tests\Integration;
+
+use Piwik\Plugins\SegmentEditor\SegmentFormatter;
+use Piwik\Plugins\SegmentEditor\SegmentList;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\Mock\FakeAccess;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Piwik\Translate;
+use Exception;
+
+/**
+ * @group SegmentFormatterTest
+ * @group SegmentFormatter
+ * @group SegmentEditor
+ * @group Plugins
+ */
+class SegmentFormatterTest extends IntegrationTestCase
+{
+ /**
+ * @var SegmentFormatter
+ */
+ private $formatter;
+
+ private $idSite;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->idSite = Fixture::createWebsite('2012-01-01 00:00:00');
+ $this->formatter = new SegmentFormatter(new SegmentList());
+
+ Translate::loadAllTranslations();
+ }
+
+ public function tearDown()
+ {
+ Translate::reset();
+ }
+
+ public function test_getHumanReadable_noSegmentGiven_ShouldReturnDefaultSegment()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = '', $this->idSite);
+ $this->assertSame('All visits', $readable);
+ }
+
+ public function test_getHumanReadable_ShouldTranslateAMetric()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = 'visitCount>5', $this->idSite);
+ $this->assertSame('Number of visits greater than "5"', $readable);
+
+ $readable = $this->formatter->getHumanReadable($segment = 'visitCount==5', $this->idSite);
+ $this->assertSame('Number of visits equals "5"', $readable);
+ }
+
+ public function test_getHumanReadable_ShouldTranslateADimension()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = 'resolution=@1024', $this->idSite);
+ $this->assertSame('Resolution contains "1024"', $readable);
+
+ $readable = $this->formatter->getHumanReadable($segment = 'resolution==1024x768', $this->idSite);
+ $this->assertSame('Resolution is "1024x768"', $readable);
+ }
+
+ public function test_getHumanReadable_ShouldCombineMultipleSegmentDefinitionsWithBooleanOperator()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = 'browserVersion!=1.0;browserEngine=$Trident', $this->idSite);
+ $this->assertSame('Browser version is not "1.0" and Browser engine ends with "Trident"', $readable);
+
+ $readable = $this->formatter->getHumanReadable($segment = 'browserVersion!=1.0,browserEngine=$Trident', $this->idSite);
+ $this->assertSame('Browser version is not "1.0" or Browser engine ends with "Trident"', $readable);
+ }
+
+ public function test_getHumanReadable_ShouldHandleAMissingValue()
+ {
+ $readable = $this->formatter->getHumanReadable($segment = 'browserVersion==', $this->idSite);
+ $this->assertSame('Browser version is null or empty', $readable);
+
+ $readable = $this->formatter->getHumanReadable($segment = 'browserVersion!=', $this->idSite);
+ $this->assertSame('Browser version is not null nor empty', $readable);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage The segment 'noTexisTinG' does not exist
+ */
+ public function test_getHumanReadable_ShouldThrowAnException_IfTheGivenSegmentNameDoesNotExist()
+ {
+ $this->formatter->getHumanReadable($segment = 'noTexisTinG==1.0', $this->idSite);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage The segment 'pageUrl=!1.0' is not valid.
+ */
+ public function test_getHumanReadable_ShouldThrowAnException_IfSegmentCannotBeParsedBecauseOfInvalidFormat()
+ {
+ $invalidOperator = '=!';
+ $this->formatter->getHumanReadable($segment = 'pageUrl' . $invalidOperator . '1.0', $this->idSite);
+ }
+
+}
diff --git a/plugins/SegmentEditor/tests/Integration/SegmentListTest.php b/plugins/SegmentEditor/tests/Integration/SegmentListTest.php
new file mode 100644
index 0000000000..3a90bb95ee
--- /dev/null
+++ b/plugins/SegmentEditor/tests/Integration/SegmentListTest.php
@@ -0,0 +1,74 @@
+<?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\SegmentEditor\tests\Integration;
+
+use Piwik\Plugins\SegmentEditor\SegmentList;
+use Piwik\Tests\Framework\Fixture;
+use Piwik\Tests\Framework\Mock\FakeAccess;
+use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
+use Exception;
+
+/**
+ * @group SegmentListTest
+ * @group SegmentList
+ * @group SegmentEditor
+ * @group Plugins
+ */
+class SegmentListTest extends IntegrationTestCase
+{
+ /**
+ * @var SegmentList
+ */
+ private $list;
+
+ private $idSite;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->idSite = Fixture::createWebsite('2012-01-01 00:00:00');
+ $this->list = new SegmentList();
+ }
+
+ public function test_findSegment_shouldFindSegmentByName_IfNameExists()
+ {
+ $segmentName = 'pageUrl';
+
+ $segment = $this->list->findSegment($segmentName, $this->idSite);
+ $this->assertInternalType('array', $segment);
+ $this->assertSame($segmentName, $segment['segment']);
+ }
+
+ public function test_findSegment_shouldNotFindSegmentByName_IfNameDoesNotExist()
+ {
+ $segment = $this->list->findSegment('aNyNotExisTinGSegmEnt', $this->idSite);
+ $this->assertNull($segment);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage checkUserHasViewAccess
+ */
+ public function test_findSegment_ShouldThrowException_IfNotEnoughPermission()
+ {
+ FakeAccess::clearAccess($superUser = false, array(1));
+
+ $segment = $this->list->findSegment('pageUrl', 999);
+ $this->assertNull($segment);
+ }
+
+ public function provideContainerConfig()
+ {
+ return array(
+ 'Piwik\Access' => new FakeAccess()
+ );
+ }
+
+}