update Piwik to version 2.16 (fixes #91)

This commit is contained in:
oliver 2016-04-10 18:55:57 +02:00
commit 47263617c5
62 changed files with 418860 additions and 226988 deletions

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -8,15 +8,17 @@
*/
namespace Piwik\Plugins\CustomVariables;
use Piwik\API\Request;
use Piwik\Archive;
use Piwik\Container\StaticContainer;
use Piwik\DataTable;
use Piwik\Date;
use Piwik\Metrics;
use Piwik\Piwik;
use Piwik\Tracker\ActionSiteSearch;
use Piwik\Plugins\Actions\Actions\ActionSiteSearch;
/**
* The Custom Variables API lets you access reports for your <a href='http://piwik.org/docs/custom-variables/' target='_blank'>Custom Variables</a> names and values.
* The Custom Variables API lets you access reports for your <a href='http://piwik.org/docs/custom-variables/' rel='noreferrer' target='_blank'>Custom Variables</a> names and values.
*
* @method static \Piwik\Plugins\CustomVariables\API getInstance()
*/
@ -32,12 +34,16 @@ class API extends \Piwik\Plugin\API
*
* @return DataTable|DataTable\Map
*/
protected function getDataTable($idSite, $period, $date, $segment, $expanded, $idSubtable)
protected function getDataTable($idSite, $period, $date, $segment, $expanded, $flat, $idSubtable)
{
$dataTable = Archive::getDataTableFromArchive(Archiver::CUSTOM_VARIABLE_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $idSubtable);
$dataTable->filter('Sort', array(Metrics::INDEX_NB_ACTIONS, 'desc', $naturalSort = false, $expanded));
$dataTable->queueFilter('ReplaceColumnNames');
$dataTable = Archive::createDataTableFromArchive(Archiver::CUSTOM_VARIABLE_RECORD_NAME, $idSite, $period, $date, $segment, $expanded, $flat, $idSubtable);
$dataTable->queueFilter('ColumnDelete', 'nb_uniq_visitors');
if ($flat) {
$dataTable->filterSubtables('Sort', array(Metrics::INDEX_NB_ACTIONS, 'desc', $naturalSort = false, $expanded));
$dataTable->queueFilterSubtables('ColumnDelete', 'nb_uniq_visitors');
}
return $dataTable;
}
@ -48,12 +54,13 @@ class API extends \Piwik\Plugin\API
* @param string|bool $segment
* @param bool $expanded
* @param bool $_leavePiwikCoreVariables
* @param bool $flat
*
* @return DataTable|DataTable\Map
*/
public function getCustomVariables($idSite, $period, $date, $segment = false, $expanded = false, $_leavePiwikCoreVariables = false)
public function getCustomVariables($idSite, $period, $date, $segment = false, $expanded = false, $_leavePiwikCoreVariables = false, $flat = false)
{
$dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded, $idSubtable = null);
$dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded, $flat, $idSubtable = null);
if ($dataTable instanceof DataTable
&& !$_leavePiwikCoreVariables
@ -66,6 +73,14 @@ class API extends \Piwik\Plugin\API
}
}
}
if ($flat) {
$dataTable->filterSubtables('Piwik\Plugins\CustomVariables\DataTable\Filter\CustomVariablesValuesFromNameId');
} else {
$dataTable->filter('AddSegmentByLabel', array('customVariableName'));
}
return $dataTable;
}
@ -90,7 +105,7 @@ class API extends \Piwik\Plugin\API
*/
public function getCustomVariablesValuesFromNameId($idSite, $period, $date, $idSubtable, $segment = false, $_leavePriceViewedColumn = false)
{
$dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded = false, $idSubtable);
$dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded = false, $flat = false, $idSubtable);
if (!$_leavePriceViewedColumn) {
$dataTable->deleteColumn('price_viewed');
@ -98,12 +113,64 @@ class API extends \Piwik\Plugin\API
// Hack Ecommerce product price tracking to display correctly
$dataTable->renameColumn('price_viewed', 'price');
}
$dataTable->queueFilter('ColumnCallbackReplace', array('label', function ($label) {
return $label == \Piwik\Plugins\CustomVariables\Archiver::LABEL_CUSTOM_VALUE_NOT_DEFINED
? Piwik::translate('General_NotDefined', Piwik::translate('CustomVariables_ColumnCustomVariableValue'))
: $label;
}));
$dataTable->filter('Piwik\Plugins\CustomVariables\DataTable\Filter\CustomVariablesValuesFromNameId');
return $dataTable;
}
/**
* Get a list of all available custom variable slots (scope + index) and which names have been used so far in
* each slot since the beginning of the website.
*
* @param int $idSite
* @return array
*/
public function getUsagesOfSlots($idSite)
{
Piwik::checkUserHasAdminAccess($idSite);
$numVars = CustomVariables::getNumUsableCustomVariables();
$usedCustomVariables = array(
'visit' => array_fill(1, $numVars, array()),
'page' => array_fill(1, $numVars, array()),
);
/** @var DataTable $customVarUsages */
$today = StaticContainer::get('CustomVariables.today');
$date = '2008-12-12,' . $today;
$customVarUsages = Request::processRequest('CustomVariables.getCustomVariables',
array('idSite' => $idSite, 'period' => 'range', 'date' => $date,
'format' => 'original')
);
foreach ($customVarUsages->getRows() as $row) {
$slots = $row->getMetadata('slots');
if (!empty($slots)) {
foreach ($slots as $slot) {
$usedCustomVariables[$slot['scope']][$slot['index']][] = array(
'name' => $row->getColumn('label'),
'nb_visits' => $row->getColumn('nb_visits'),
'nb_actions' => $row->getColumn('nb_actions'),
);
}
}
}
$grouped = array();
foreach ($usedCustomVariables as $scope => $scopes) {
foreach ($scopes as $index => $cvars) {
$grouped[] = array(
'scope' => $scope,
'index' => $index,
'usages' => $cvars
);
}
}
return $grouped;
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -8,13 +8,13 @@
*/
namespace Piwik\Plugins\CustomVariables;
use Piwik\Common;
use Piwik\Config;
use Piwik\DataAccess\LogAggregator;
use Piwik\DataArray;
use Piwik\DataTable;
use Piwik\Metrics;
use Piwik\Tracker;
use Piwik\Tracker\GoalManager;
use Piwik\Tracker;
require_once PIWIK_INCLUDE_PATH . '/libs/PiwikTracker/PiwikTracker.php';
@ -35,11 +35,14 @@ class Archiver extends \Piwik\Plugin\Archiver
protected $maximumRowsInSubDataTable;
protected $newEmptyRow;
private $metadata = array();
private $metadataFlat = array();
function __construct($processor)
{
parent::__construct($processor);
if($processor->getParams()->getSite()->isEcommerceEnabled()) {
if ($processor->getParams()->getSite()->isEcommerceEnabled()) {
$this->maximumRowsInDataTableLevelZero = self::MAX_ROWS_WHEN_ECOMMERCE;
$this->maximumRowsInSubDataTable = self::MAX_ROWS_WHEN_ECOMMERCE;
} else {
@ -50,16 +53,23 @@ class Archiver extends \Piwik\Plugin\Archiver
public function aggregateMultipleReports()
{
$columnsAggregationOperation = array('slots' => 'uniquearraymerge');
$this->getProcessor()->aggregateDataTableRecords(
self::CUSTOM_VARIABLE_RECORD_NAME, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable,
$columnToSort = Metrics::INDEX_NB_VISITS);
self::CUSTOM_VARIABLE_RECORD_NAME,
$this->maximumRowsInDataTableLevelZero,
$this->maximumRowsInSubDataTable,
$columnToSort = Metrics::INDEX_NB_VISITS,
$columnsAggregationOperation,
$columnsToRenameAfterAggregation = null,
$countRowsRecursive = array());
}
public function aggregateDayReport()
{
$this->dataArray = new DataArray();
$maxCustomVariables = CustomVariables::getMaxCustomVariables();
$maxCustomVariables = CustomVariables::getNumUsableCustomVariables();
for ($i = 1; $i <= $maxCustomVariables; $i++) {
$this->aggregateCustomVariable($i);
}
@ -67,6 +77,16 @@ class Archiver extends \Piwik\Plugin\Archiver
$this->removeVisitsMetricsFromActionsAggregate();
$this->dataArray->enrichMetricsWithConversions();
$table = $this->dataArray->asDataTable();
foreach ($table->getRows() as $row) {
$label = $row->getColumn('label');
if (!empty($this->metadata[$label])) {
foreach ($this->metadata[$label] as $name => $value) {
$row->addMetadata($name, $value);
}
}
}
$blob = $table->getSerialized(
$this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable,
$columnToSort = Metrics::INDEX_NB_VISITS
@ -111,6 +131,8 @@ class Archiver extends \Piwik\Plugin\Archiver
$key = $row[$keyField];
$value = $this->cleanCustomVarValue($row[$valueField]);
$this->addMetadata($keyField, $key, Model::SCOPE_VISIT);
$this->dataArray->sumMetricsVisits($key, $row);
$this->dataArray->sumMetricsVisitsPivot($key, $value, $row);
}
@ -130,6 +152,8 @@ class Archiver extends \Piwik\Plugin\Archiver
$key = $row[$keyField];
$value = $this->cleanCustomVarValue($row[$valueField]);
$this->addMetadata($keyField, $key, Model::SCOPE_PAGE);
$alreadyAggregated = $this->aggregateEcommerceCategories($key, $value, $row);
if (!$alreadyAggregated) {
$this->aggregateActionByKeyAndValue($key, $value, $row);
@ -138,6 +162,22 @@ class Archiver extends \Piwik\Plugin\Archiver
}
}
private function addMetadata($keyField, $label, $scope)
{
$index = (int) str_replace('custom_var_k', '', $keyField);
if (!array_key_exists($label, $this->metadata)) {
$this->metadata[$label] = array('slots' => array());
}
$uniqueId = $label . 'scope' . $scope . 'index' . $index;
if (!isset($this->metadataFlat[$uniqueId])) {
$this->metadata[$label]['slots'][] = array('scope' => $scope, 'index' => $index);
$this->metadataFlat[$uniqueId] = true;
}
}
/**
* @param string $key
* @param string $value
@ -154,7 +194,7 @@ class Archiver extends \Piwik\Plugin\Archiver
if (substr($value, -2) != '"]') {
$value .= '"]';
}
$decoded = @Common::json_decode($value);
$decoded = json_decode($value);
if (is_array($decoded)) {
$count = 0;
foreach ($decoded as $category) {
@ -198,12 +238,26 @@ class Archiver extends \Piwik\Plugin\Archiver
}
while ($row = $query->fetch()) {
$key = $row[$keyField];
$value = $this->cleanCustomVarValue($row[$valueField]);
$this->dataArray->sumMetricsGoals($key, $row);
$this->dataArray->sumMetricsGoalsPivot($key, $value, $row);
}
}
/**
* Delete Visit, Unique Visitor and Users metric from 'page' scope custom variables.
*
* - Custom variables of 'visit' scope: it is expected that these ones have the "visit" column set.
* - Custom variables of 'page' scope: we cannot process "Visits" count for these.
* Why?
* "Actions" column is processed with a SELECT count(*).
* A same visit can set the same custom variable of 'page' scope multiple times.
* We cannot sum the values of count(*) as it would be incorrect.
* The way we could process "Visits" Metric for 'page' scope variable is to issue a count(Distinct *) or so,
* but it is no implemented yet (this would likely be very slow for high traffic sites).
*
*/
protected function removeVisitsMetricsFromActionsAggregate()
{
$dataArray = & $this->dataArray->getDataArray();
@ -213,6 +267,7 @@ class Archiver extends \Piwik\Plugin\Archiver
) {
unset($row[Metrics::INDEX_NB_UNIQ_VISITORS]);
unset($row[Metrics::INDEX_NB_VISITS]);
unset($row[Metrics::INDEX_NB_USERS]);
}
}
}

View file

@ -0,0 +1,48 @@
<?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\DataTable;
use Piwik\Piwik;
use Piwik\Plugin\Dimension\VisitDimension;
use Piwik\Plugin\Segment;
use Piwik\Plugins\CustomVariables\CustomVariables;
class Base extends VisitDimension
{
protected function configureSegmentsFor($segmentNameSuffix)
{
$numCustomVariables = CustomVariables::getNumUsableCustomVariables();
$segment = new Segment();
$segment->setType('dimension');
$segment->setSegment('customVariable' . $segmentNameSuffix);
$segment->setName($this->getName() . ' (' . Piwik::translate('CustomVariables_ScopeVisit') . ')');
$segment->setCategory('CustomVariables_CustomVariables');
$segment->setUnionOfSegments($this->getSegmentColumns('customVariable' . $segmentNameSuffix, $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->setUnionOfSegments($this->getSegmentColumns('customVariablePage' . $segmentNameSuffix, $numCustomVariables));
$this->addSegment($segment);
}
private function getSegmentColumns($column, $numCustomVariables)
{
$columns = array();
for ($i = 1; $i <= $numCustomVariables; ++$i) {
$columns[] = $column . $i;
}
return $columns;
}
}

View file

@ -0,0 +1,24 @@
<?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;
class CustomVariableName extends Base
{
protected function configureSegments()
{
$this->configureSegmentsFor('Name');
}
public function getName()
{
return Piwik::translate('CustomVariables_ColumnCustomVariableName');
}
}

View file

@ -0,0 +1,24 @@
<?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;
class CustomVariableValue extends Base
{
protected function configureSegments()
{
$this->configureSegmentsFor('Value');
}
public function getName()
{
return Piwik::translate('CustomVariables_ColumnCustomVariableValue');
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -13,7 +13,6 @@ use Piwik\Common;
use Piwik\Plugin\ConsoleCommand;
use Piwik\Plugins\CustomVariables\CustomVariables;
use Piwik\Plugins\CustomVariables\Model;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -29,7 +28,7 @@ class Info extends ConsoleCommand
protected function execute(InputInterface $input, OutputInterface $output)
{
$maxVars = CustomVariables::getMaxCustomVariables();
$maxVars = CustomVariables::getNumUsableCustomVariables();
if ($this->hasEverywhereSameAmountOfVariables()) {
$this->writeSuccessMessage($output, array(
@ -63,7 +62,7 @@ class Info extends ConsoleCommand
return false;
}
}
return true;
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -10,11 +10,10 @@
namespace Piwik\Plugins\CustomVariables\Commands;
use Piwik\Plugin\ConsoleCommand;
use Piwik\Tracker\Cache;
use Piwik\Plugins\CustomVariables\Model;
use Piwik\Tracker\Cache;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
@ -49,32 +48,27 @@ class SetNumberOfCustomVariables extends ConsoleCommand
return;
}
$output->writeln('');
$output->writeln(sprintf('Configuring Piwik for %d custom variables', $numVarsToSet));
foreach (Model::getScopes() as $scope) {
$this->printChanges($scope, $numVarsToSet, $output);
}
if (!$this->confirmChange($output)) {
if ($input->isInteractive() && !$this->confirmChange($output)) {
return;
}
$output->writeln('');
$output->writeln('Starting to apply changes');
$output->writeln('');
$this->progress = $this->initProgress($numChangesToPerform, $output);
foreach (Model::getScopes() as $scope) {
$this->performChange($scope, $numVarsToSet, $output);
}
Cache::clearCacheGeneral();
$this->progress->finish();
@ -204,7 +198,7 @@ class SetNumberOfCustomVariables extends ConsoleCommand
$numCurrentCustomVars = $model->getCurrentNumCustomVars();
$numChangesToPerform += $this->getAbsoluteDifference($numCurrentCustomVars, $numVarsToSet);
}
return $numChangesToPerform;
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -8,29 +8,20 @@
*/
namespace Piwik\Plugins\CustomVariables;
use Piwik\Common;
use Piwik\DataTable;
use Piwik\Piwik;
use Piwik\View;
use Piwik\ViewDataTable\Factory;
/**
*/
class Controller extends \Piwik\Plugin\Controller
{
public function index()
public function manage()
{
return View::singleReport(
Piwik::translate('CustomVariables_CustomVariables'),
$this->getCustomVariables(true));
$idSite = Common::getRequestVar('idSite');
Piwik::checkUserHasAdminAccess($idSite);
return $this->renderTemplate('manage', array());
}
public function getCustomVariables()
{
return $this->renderReport(__FUNCTION__);
}
public function getCustomVariablesValuesFromNameId()
{
return $this->renderReport(__FUNCTION__);
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -9,48 +9,24 @@
namespace Piwik\Plugins\CustomVariables;
use Piwik\ArchiveProcessor;
use Piwik\Menu\MenuMain;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Tracker;
use Piwik\WidgetsList;
use Piwik\Tracker\Cache;
use Piwik\Tracker;
/**
*/
class CustomVariables extends \Piwik\Plugin
{
public function getInformation()
{
$info = parent::getInformation();
$info['description'] .= ' <br/>Required to use <a href="http://piwik.org/docs/ecommerce-analytics/">Ecommerce Analytics</a> feature!';
return $info;
}
/**
* @see Piwik\Plugin::getListHooksRegistered
* @see Piwik\Plugin::registerEvents
*/
public function getListHooksRegistered()
public function registerEvents()
{
$hooks = array(
'WidgetsList.addWidgets' => 'addWidgets',
'Menu.Reporting.addItems' => 'addMenus',
'Goals.getReportsWithGoalMetrics' => 'getReportsWithGoalMetrics',
'API.getReportMetadata' => 'getReportMetadata',
return array(
'API.getSegmentDimensionMetadata' => 'getSegmentsMetadata',
'ViewDataTable.configure' => 'configureViewDataTable'
'Live.getAllVisitorDetails' => 'extendVisitorDetails',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
);
return $hooks;
}
public function addWidgets()
{
WidgetsList::add('General_Visitors', 'CustomVariables_CustomVariables', 'CustomVariables', 'getCustomVariables');
}
public function addMenus()
{
MenuMain::getInstance()->add('General_Visitors', 'CustomVariables_CustomVariables', array('module' => 'CustomVariables', 'action' => 'index'), $display = true, $order = 50);
}
public function install()
@ -63,6 +39,24 @@ class CustomVariables extends \Piwik\Plugin
Model::uninstall();
}
public function extendVisitorDetails(&$visitor, $details)
{
$customVariables = array();
$maxCustomVariables = self::getNumUsableCustomVariables();
for ($i = 1; $i <= $maxCustomVariables; $i++) {
if (!empty($details['custom_var_k' . $i])) {
$customVariables[$i] = array(
'customVariableName' . $i => $details['custom_var_k' . $i],
'customVariableValue' . $i => $details['custom_var_v' . $i],
);
}
}
$visitor['customVariables'] = $customVariables;
}
/**
* There are also some hardcoded places in JavaScript
* @return int
@ -72,61 +66,50 @@ class CustomVariables extends \Piwik\Plugin
return 200;
}
public static function getMaxCustomVariables()
/**
* Returns the number of available custom variables that can be used.
*
* "Can be used" is identifed by the minimum number of available custom variables across all relevant tables. Eg
* if there are 6 custom variables installed in log_visit but only 5 in log_conversion, we consider only 5 custom
* variables as usable.
* @return int
*/
public static function getNumUsableCustomVariables()
{
$cache = Cache::getCacheGeneral();
$cacheKey = 'CustomVariables.MaxNumCustomVariables';
$cacheKey = 'CustomVariables.NumUsableCustomVariables';
if (!array_key_exists($cacheKey, $cache)) {
$maxCustomVar = 0;
$minCustomVar = null;
foreach (Model::getScopes() as $scope) {
$model = new Model($scope);
$highestIndex = $model->getHighestCustomVarIndex();
if ($highestIndex > $maxCustomVar) {
$maxCustomVar = $highestIndex;
if (!isset($minCustomVar)) {
$minCustomVar = $highestIndex;
}
if ($highestIndex < $minCustomVar) {
$minCustomVar = $highestIndex;
}
}
$cache[$cacheKey] = $maxCustomVar;
if (!isset($minCustomVar)) {
$minCustomVar = 0;
}
$cache[$cacheKey] = $minCustomVar;
Cache::setCacheGeneral($cache);
}
return $cache[$cacheKey];
}
/**
* Returns metadata for available reports
*/
public function getReportMetadata(&$reports)
{
$documentation = Piwik::translate('CustomVariables_CustomVariablesReportDocumentation',
array('<br />', '<a href="http://piwik.org/docs/custom-variables/" target="_blank">', '</a>'));
$reports[] = array('category' => Piwik::translate('General_Visitors'),
'name' => Piwik::translate('CustomVariables_CustomVariables'),
'module' => 'CustomVariables',
'action' => 'getCustomVariables',
'actionToLoadSubTables' => 'getCustomVariablesValuesFromNameId',
'dimension' => Piwik::translate('CustomVariables_ColumnCustomVariableName'),
'documentation' => $documentation,
'order' => 10);
$reports[] = array('category' => Piwik::translate('General_Visitors'),
'name' => Piwik::translate('CustomVariables_CustomVariables'),
'module' => 'CustomVariables',
'action' => 'getCustomVariablesValuesFromNameId',
'dimension' => Piwik::translate('CustomVariables_ColumnCustomVariableValue'),
'documentation' => $documentation,
'isSubtableReport' => true,
'order' => 15);
}
public function getSegmentsMetadata(&$segments)
{
$maxCustomVariables = self::getMaxCustomVariables();
$maxCustomVariables = self::getNumUsableCustomVariables();
for ($i = 1; $i <= $maxCustomVariables; $i++) {
$segments[] = array(
@ -164,52 +147,35 @@ class CustomVariables extends \Piwik\Plugin
}
}
/**
* Adds Goal dimensions, so that the dimensions are displayed in the UI Goal Overview page
*/
public function getReportsWithGoalMetrics(&$dimensions)
public function getClientSideTranslationKeys(&$translationKeys)
{
$dimensions[] = array('category' => Piwik::translate('General_Visit'),
'name' => Piwik::translate('CustomVariables_CustomVariables'),
'module' => 'CustomVariables',
'action' => 'getCustomVariables',
);
$translationKeys[] = 'CustomVariables_CustomVariables';
$translationKeys[] = 'CustomVariables_ManageDescription';
$translationKeys[] = 'CustomVariables_ScopeX';
$translationKeys[] = 'CustomVariables_Index';
$translationKeys[] = 'CustomVariables_Usages';
$translationKeys[] = 'CustomVariables_Unused';
$translationKeys[] = 'CustomVariables_CreateNewSlot';
$translationKeys[] = 'CustomVariables_UsageDetails';
$translationKeys[] = 'CustomVariables_CurrentAvailableCustomVariables';
$translationKeys[] = 'CustomVariables_ToCreateCustomVarExecute';
$translationKeys[] = 'CustomVariables_CreatingCustomVariableTakesTime';
$translationKeys[] = 'CustomVariables_SlotsReportIsGeneratedOverTime';
$translationKeys[] = 'General_Loading';
$translationKeys[] = 'General_TrackingScopeVisit';
$translationKeys[] = 'General_TrackingScopePage';
}
public function configureViewDataTable(ViewDataTable $view)
public function getStylesheetFiles(&$stylesheets)
{
switch ($view->requestConfig->apiMethodToRequestDataTable) {
case 'CustomVariables.getCustomVariables':
$this->configureViewForGetCustomVariables($view);
break;
case 'CustomVariables.getCustomVariablesValuesFromNameId':
$this->configureViewForGetCustomVariablesValuesFromNameId($view);
break;
}
$stylesheets[] = "plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.directive.less";
}
private function configureViewForGetCustomVariables(ViewDataTable $view)
public function getJsFiles(&$jsFiles)
{
$footerMessage = Piwik::translate('CustomVariables_TrackingHelp',
array('<a target="_blank" href="http://piwik.org/docs/custom-variables/">', '</a>'));
$view->config->columns_to_display = array('label', 'nb_actions', 'nb_visits');
$view->config->show_goals = true;
$view->config->subtable_controller_action = 'getCustomVariablesValuesFromNameId';
$view->config->show_footer_message = $footerMessage;
$view->config->addTranslation('label', Piwik::translate('CustomVariables_ColumnCustomVariableName'));
$view->requestConfig->filter_sort_column = 'nb_actions';
$view->requestConfig->filter_sort_order = 'desc';
$jsFiles[] = "plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.model.js";
$jsFiles[] = "plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.controller.js";
$jsFiles[] = "plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.directive.js";
}
private function configureViewForGetCustomVariablesValuesFromNameId(ViewDataTable $view)
{
$view->config->columns_to_display = array('label', 'nb_actions', 'nb_visits');
$view->config->show_goals = true;
$view->config->show_search = false;
$view->config->show_exclude_low_population = false;
$view->config->addTranslation('label', Piwik::translate('CustomVariables_ColumnCustomVariableValue'));
$view->requestConfig->filter_sort_column = 'nb_actions';
$view->requestConfig->filter_sort_order = 'desc';
}
}

View file

@ -0,0 +1,42 @@
<?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\DataTable\Filter;
use Piwik\DataTable\BaseFilter;
use Piwik\DataTable\Row;
use Piwik\DataTable;
use Piwik\Piwik;
class CustomVariablesValuesFromNameId extends BaseFilter
{
/**
* Constructor.
*
* @param DataTable $table The table to eventually filter.
*/
public function __construct($table)
{
parent::__construct($table);
}
/**
* @param DataTable $table
*/
public function filter($table)
{
$notDefinedLabel = Piwik::translate('General_NotDefined', Piwik::translate('CustomVariables_ColumnCustomVariableValue'));
$table->queueFilter('ColumnCallbackReplace', array('label', function ($label) use ($notDefinedLabel) {
return $label == \Piwik\Plugins\CustomVariables\Archiver::LABEL_CUSTOM_VALUE_NOT_DEFINED
? $notDefinedLabel
: $label;
}));
}
}

View file

@ -0,0 +1,33 @@
<?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;
use Piwik\Common;
use Piwik\Menu\MenuUser;
use Piwik\Piwik;
use Piwik\Plugins\UsersManager\UserPreferences;
/**
* This class allows you to add, remove or rename menu items.
* To configure a menu (such as Admin Menu, Reporting Menu, User Menu...) simply call the corresponding methods as
* described in the API-Reference http://developer.piwik.org/api-reference/Piwik/Menu/MenuAbstract
*/
class Menu extends \Piwik\Plugin\Menu
{
public function configureUserMenu(MenuUser $menu)
{
$userPreferences = new UserPreferences();
$default = $userPreferences->getDefaultWebsiteId();
$idSite = Common::getRequestVar('idSite', $default, 'int');
if (Piwik::isUserHasAdminAccess($idSite)) {
$menu->addManageItem('Custom Variables', $this->urlForAction('manage'), $orderId = 15);
}
}
}

View file

@ -1,6 +1,6 @@
<?php
/**
* Piwik - Open source web analytics
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
@ -15,11 +15,14 @@ use Piwik\Log;
class Model
{
const SCOPE_PAGE = 'log_link_visit_action';
const SCOPE_VISIT = 'log_visit';
const SCOPE_CONVERSION = 'log_conversion';
const DEFAULT_CUSTOM_VAR_COUNT = 5;
const SCOPE_PAGE = 'page';
const SCOPE_VISIT = 'visit';
const SCOPE_CONVERSION = 'conversion';
private $scope = null;
private $table = null;
public function __construct($scope)
{
@ -28,19 +31,25 @@ class Model
}
$this->scope = $scope;
$this->table = Common::prefixTable($this->getTableNameFromScope($scope));
}
private function getTableNameFromScope($scope)
{
// actually we should have a class for each scope but don't want to overengineer it for now
switch ($scope) {
case self::SCOPE_PAGE:
return 'log_link_visit_action';
case self::SCOPE_VISIT:
return 'log_visit';
case self::SCOPE_CONVERSION:
return 'log_conversion';
}
}
public function getScopeName()
{
// actually we should have a class for each scope but don't want to overengineer it for now
switch ($this->scope) {
case self::SCOPE_PAGE:
return 'Page';
case self::SCOPE_VISIT:
return 'Visit';
case self::SCOPE_CONVERSION:
return 'Conversion';
}
return ucfirst($this->scope);
}
/**
@ -95,8 +104,7 @@ class Model
private function getCustomVarColumnNames()
{
$dbTable = $this->getDbTableName();
$columns = Db::getColumnNamesFromTable($dbTable);
$columns = Db::getColumnNamesFromTable($this->table);
$customVarColumns = array_filter($columns, function ($column) {
return false !== strpos($column, 'custom_var_');
@ -107,14 +115,13 @@ class Model
public function removeCustomVariable()
{
$dbTable = $this->getDbTableName();
$index = $this->getHighestCustomVarIndex();
$index = $this->getHighestCustomVarIndex();
if ($index < 1) {
return null;
}
Db::exec(sprintf('ALTER TABLE %s ', $dbTable)
Db::exec(sprintf('ALTER TABLE %s ', $this->table)
. sprintf('DROP COLUMN custom_var_k%d,', $index)
. sprintf('DROP COLUMN custom_var_v%d;', $index));
@ -123,22 +130,16 @@ class Model
public function addCustomVariable()
{
$dbTable = $this->getDbTableName();
$index = $this->getHighestCustomVarIndex() + 1;
$maxLen = CustomVariables::getMaxLengthCustomVariables();
$index = $this->getHighestCustomVarIndex() + 1;
$maxLen = CustomVariables::getMaxLengthCustomVariables();
Db::exec(sprintf('ALTER TABLE %s ', $dbTable)
Db::exec(sprintf('ALTER TABLE %s ', $this->table)
. sprintf('ADD COLUMN custom_var_k%d VARCHAR(%d) DEFAULT NULL,', $index, $maxLen)
. sprintf('ADD COLUMN custom_var_v%d VARCHAR(%d) DEFAULT NULL;', $index, $maxLen));
return $index;
}
private function getDbTableName()
{
return Common::prefixTable($this->scope);
}
public static function getCustomVariableIndexFromFieldName($fieldName)
{
$onlyNumber = str_replace(array('custom_var_k', 'custom_var_v'), '', $fieldName);
@ -159,14 +160,14 @@ class Model
$model = new Model($scope);
try {
$maxCustomVars = 5;
$maxCustomVars = self::DEFAULT_CUSTOM_VAR_COUNT;
$customVarsToAdd = $maxCustomVars - $model->getCurrentNumCustomVars();
for ($index = 0; $index < $customVarsToAdd; $index++) {
$model->addCustomVariable();
}
} catch (\Exception $e) {
Log::warning('Failed to add custom variable: ' . $e->getMessage());
Log::error('Failed to add custom variable: ' . $e->getMessage());
}
}
}

View file

@ -0,0 +1,20 @@
<?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\Reports;
abstract class Base extends \Piwik\Plugin\Report
{
protected $defaultSortColumn = 'nb_actions';
protected function init()
{
$this->category = 'General_Visitors';
}
}

View file

@ -0,0 +1,75 @@
<?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\Reports;
use Piwik\DataTable;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CustomVariables\Columns\CustomVariableName;
class GetCustomVariables extends Base
{
protected function init()
{
parent::init();
$this->dimension = new CustomVariableName();
$this->name = Piwik::translate('CustomVariables_CustomVariables');
$this->documentation = Piwik::translate('CustomVariables_CustomVariablesReportDocumentation',
array('<br />', '<a href="http://piwik.org/docs/custom-variables/" rel="noreferrer" target="_blank">', '</a>'));
$this->actionToLoadSubTables = 'getCustomVariablesValuesFromNameId';
$this->order = 10;
$this->widgetTitle = 'CustomVariables_CustomVariables';
$this->menuTitle = 'CustomVariables_CustomVariables';
$this->hasGoalMetrics = true;
}
public function configureView(ViewDataTable $view)
{
$view->config->columns_to_display = array('label', 'nb_actions', 'nb_visits');
$view->config->addTranslation('label', Piwik::translate('CustomVariables_ColumnCustomVariableName'));
$view->requestConfig->filter_sort_column = 'nb_actions';
$view->requestConfig->filter_sort_order = 'desc';
$that = $this;
$view->config->filters[] = function (DataTable $table) use ($view, $that) {
if($that->isReportContainsUnsetVisitsColumns($table)) {
$message = $that->getFooterMessageExplanationMissingMetrics();
$view->config->show_footer_message = $message;
}
};
}
/**
* @return array
*/
public function getFooterMessageExplanationMissingMetrics()
{
$metrics = sprintf("'%s', '%s' %s '%s'",
Piwik::translate('General_ColumnNbVisits'),
Piwik::translate('General_ColumnNbUniqVisitors'),
Piwik::translate('General_And'),
Piwik::translate('General_ColumnNbUsers')
);
$messageStart = Piwik::translate('CustomVariables_MetricsAreOnlyAvailableForVisitScope', array($metrics, "'visit'"));
$messageEnd = Piwik::translate('CustomVariables_MetricsNotAvailableForPageScope', array("'page'", '\'-\''));
return $messageStart . ' ' . $messageEnd;
}
/**
* @return bool
*/
public function isReportContainsUnsetVisitsColumns(DataTable $report)
{
$visits = $report->getColumn('nb_visits');
$isVisitsMetricsSometimesUnset = in_array(false, $visits);
return $isVisitsMetricsSometimesUnset;
}
}

View file

@ -0,0 +1,39 @@
<?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\Reports;
use Piwik\Piwik;
use Piwik\Plugin\ViewDataTable;
use Piwik\Plugins\CustomVariables\Columns\CustomVariableValue;
class GetCustomVariablesValuesFromNameId extends Base
{
protected function init()
{
parent::init();
$this->dimension = new CustomVariableValue();
$this->name = Piwik::translate('CustomVariables_CustomVariables');
$this->documentation = Piwik::translate('CustomVariables_CustomVariablesReportDocumentation',
array('<br />', '<a href="http://piwik.org/docs/custom-variables/" rel="noreferrer" target="_blank">', '</a>'));
$this->isSubtableReport = true;
$this->order = 15;
}
public function configureView(ViewDataTable $view)
{
$view->config->columns_to_display = array('label', 'nb_actions', 'nb_visits');
$view->config->show_goals = true;
$view->config->show_search = false;
$view->config->show_exclude_low_population = false;
$view->config->addTranslation('label', Piwik::translate('CustomVariables_ColumnCustomVariableValue'));
$view->requestConfig->filter_sort_column = 'nb_actions';
$view->requestConfig->filter_sort_order = 'desc';
}
}

View file

@ -0,0 +1,88 @@
<?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\Tracker;
use Piwik\Common;
use Piwik\Plugins\CustomVariables\Model;
use Piwik\Tracker\Action;
use Piwik\Tracker\Request;
use Piwik\Tracker\RequestProcessor;
use Piwik\Tracker\Visit\VisitProperties;
/**
* Handles tracking of visit level custom variables.
*
* ### Request Metadata
*
* Defines the following request metadata for the **CustomVariables** plugin:
*
* * **visitCustomVariables**: An array of custom variable names & values. The data is stored
* as log_visit column name/value pairs, eg,
*
* ```
* array(
* 'custom_var_k1' => 'the name',
* 'custom_var_v1' => 'the value',
* ...
* )
* ```
*/
class CustomVariablesRequestProcessor extends RequestProcessor
{
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 = Model::SCOPE_VISIT);
if (!empty($visitorCustomVariables)) {
Common::printDebug("Visit level Custom Variables: ");
Common::printDebug($visitorCustomVariables);
}
$request->setMetadata('CustomVariables', 'visitCustomVariables', $visitorCustomVariables);
}
public function onNewVisit(VisitProperties $visitProperties, Request $request)
{
$visitCustomVariables = $request->getMetadata('CustomVariables', 'visitCustomVariables');
if (!empty($visitCustomVariables)) {
$visitProperties->setProperties(array_merge($visitProperties->getProperties(), $visitCustomVariables));
}
}
public function onExistingVisit(&$valuesToUpdate, VisitProperties $visitProperties, Request $request)
{
$visitCustomVariables = $request->getMetadata('CustomVariables', 'visitCustomVariables');
if (!empty($visitCustomVariables)) {
$valuesToUpdate = array_merge($valuesToUpdate, $visitCustomVariables);
}
}
public function afterRequestProcessed(VisitProperties $visitProperties, Request $request)
{
$action = $request->getMetadata('Actions', 'action');
if (empty($action) || !($action instanceof Action)) {
return;
}
$customVariables = $action->getCustomVariables();
if (!empty($customVariables)) {
Common::printDebug("Page level Custom Variables: ");
Common::printDebug($customVariables);
foreach ($customVariables as $field => $value) {
$action->setCustomField($field, $value);
}
}
}
}

View file

@ -0,0 +1,22 @@
/*!
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
(function () {
angular.module('piwikApp').controller('ManageCustomVarsController', ManageCustomVarsController);
ManageCustomVarsController.$inject = ['manageCustomVarsModel', 'piwik', '$filter'];
function ManageCustomVarsController(manageCustomVarsModel, piwik, $filter) {
manageCustomVarsModel.fetchUsages();
this.model = manageCustomVarsModel;
this.siteName = piwik.siteName;
this.scopes = [
{value: 'visit', name: _pk_translate('General_TrackingScopeVisit')},
{value: 'page', name: _pk_translate('General_TrackingScopePage')}
];
}
})();

View file

@ -0,0 +1,54 @@
<div class="manageCustomVars">
<h2 piwik-enriched-headline help-url="http://piwik.org/docs/custom-variables/">{{ 'CustomVariables_CustomVariables'|translate }}</h2>
<p>
<span ng-bind-html="'CustomVariables_ManageDescription'|translate:manageCustomVars.siteName"></span>
</p>
<div class="alert alert-info" ng-show="!manageCustomVars.model.isLoading && manageCustomVars.model.hasCustomVariablesInGeneral && !manageCustomVars.model.hasAtLeastOneUsage">
{{ 'CustomVariables_SlotsReportIsGeneratedOverTime'|translate }}
</div>
<div ng-repeat="scope in manageCustomVars.scopes">
<h2 class="secondary">{{ 'CustomVariables_ScopeX'|translate:(scope.name) }}</h2>
<table class="dataTable entityTable">
<thead>
<tr>
<th>{{'CustomVariables_Index'|translate }}</th>
<th>{{'CustomVariables_Usages'|translate }}</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="3" ng-show="manageCustomVars.model.isLoading">{{ 'General_Loading'|translate }}</td>
</tr>
<tr ng-repeat="customVariables in manageCustomVars.model.customVariables|filter:{scope: scope.value}">
<td class="index">{{ customVariables.index }}</td>
<td>
<span ng-show="(customVariables.usages|length) === 0"
class="unused">{{'CustomVariables_Unused'|translate }}</span>
<span ng-show="customVariables.usages|length" ng-repeat="cvar in customVariables.usages|orderBy:'-nb_actions'">
<span title="{{ 'CustomVariables_UsageDetails'|translate:(cvar.nb_visits ? cvar.nb_visits : 0):(cvar.nb_actions ? cvar.nb_actions : 0) }}">{{ cvar.name }}</span><span ng-show="!$last">, </span>
</span>
</td>
</tr>
</tbody>
</table>
</div>
<h2 class="secondary" ng-show="!manageCustomVars.model.isLoading">{{ 'CustomVariables_CreateNewSlot'|translate }}</h2>
<p ng-show="!manageCustomVars.model.isLoading">
{{ 'CustomVariables_CreatingCustomVariableTakesTime'|translate }}
<br /><br />
<span ng-bind-html="'CustomVariables_CurrentAvailableCustomVariables'|translate:('<strong>'+manageCustomVars.model.numSlotsAvailable+'</strong>')"></span>
<br />
<br />
{{ 'CustomVariables_ToCreateCustomVarExecute'|translate }}
<br />
<br />
<code>./console customvariables:set-max-custom-variables {{ manageCustomVars.model.numSlotsAvailable + 1 }}</code>
</p>
</div>

View file

@ -0,0 +1,26 @@
/*!
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
/**
* Usage:
* <div piwik-manage-custom-vars>
*/
(function () {
angular.module('piwikApp').directive('piwikManageCustomVars', piwikManageCustomVars);
piwikManageCustomVars.$inject = ['piwik'];
function piwikManageCustomVars(piwik){
return {
restrict: 'A',
scope: {},
templateUrl: 'plugins/CustomVariables/angularjs/manage-custom-vars/manage-custom-vars.directive.html?cb=' + piwik.cacheBuster,
controller: 'ManageCustomVarsController',
controllerAs: 'manageCustomVars'
};
}
})();

View file

@ -0,0 +1,18 @@
.manageCustomVars {
.unused {
color: @color-silver;
}
table, p {
width: 900px;
}
.alert-info {
margin-top: 15px;
}
.scope, .index {
width: 90px;
max-width: 90px;
}
}

Some files were not shown because too many files have changed in this diff Show more