hide map for Character groups Quest Stations when there are no stations

This commit is contained in:
oliver 2016-04-09 13:44:37 +02:00
commit df14dfafc3
4371 changed files with 1220224 additions and 0 deletions

View file

@ -0,0 +1,109 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\CustomVariables;
use Piwik\Archive;
use Piwik\DataTable;
use Piwik\Date;
use Piwik\Metrics;
use Piwik\Piwik;
use Piwik\Tracker\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.
*
* @method static \Piwik\Plugins\CustomVariables\API getInstance()
*/
class API extends \Piwik\Plugin\API
{
/**
* @param int $idSite
* @param string $period
* @param Date $date
* @param string $segment
* @param bool $expanded
* @param int $idSubtable
*
* @return DataTable|DataTable\Map
*/
protected function getDataTable($idSite, $period, $date, $segment, $expanded, $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->queueFilter('ColumnDelete', 'nb_uniq_visitors');
return $dataTable;
}
/**
* @param int $idSite
* @param string $period
* @param Date $date
* @param string|bool $segment
* @param bool $expanded
* @param bool $_leavePiwikCoreVariables
*
* @return DataTable|DataTable\Map
*/
public function getCustomVariables($idSite, $period, $date, $segment = false, $expanded = false, $_leavePiwikCoreVariables = false)
{
$dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded, $idSubtable = null);
if ($dataTable instanceof DataTable
&& !$_leavePiwikCoreVariables
) {
$mapping = self::getReservedCustomVariableKeys();
foreach ($mapping as $name) {
$row = $dataTable->getRowFromLabel($name);
if ($row) {
$dataTable->deleteRow($dataTable->getRowIdFromLabel($name));
}
}
}
return $dataTable;
}
/**
* @ignore
* @return array
*/
public static function getReservedCustomVariableKeys()
{
return array('_pks', '_pkn', '_pkc', '_pkp', ActionSiteSearch::CVAR_KEY_SEARCH_COUNT, ActionSiteSearch::CVAR_KEY_SEARCH_CATEGORY);
}
/**
* @param int $idSite
* @param string $period
* @param Date $date
* @param int $idSubtable
* @param string|bool $segment
* @param bool $_leavePriceViewedColumn
*
* @return DataTable|DataTable\Map
*/
public function getCustomVariablesValuesFromNameId($idSite, $period, $date, $idSubtable, $segment = false, $_leavePriceViewedColumn = false)
{
$dataTable = $this->getDataTable($idSite, $period, $date, $segment, $expanded = false, $idSubtable);
if (!$_leavePriceViewedColumn) {
$dataTable->deleteColumn('price_viewed');
} else {
// 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;
}));
return $dataTable;
}
}

View file

@ -0,0 +1,220 @@
<?php
/**
* Piwik - Open source web analytics
*
* @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\Config;
use Piwik\DataAccess\LogAggregator;
use Piwik\DataArray;
use Piwik\Metrics;
use Piwik\Tracker;
use Piwik\Tracker\GoalManager;
require_once PIWIK_INCLUDE_PATH . '/libs/PiwikTracker/PiwikTracker.php';
class Archiver extends \Piwik\Plugin\Archiver
{
const LABEL_CUSTOM_VALUE_NOT_DEFINED = "Value not defined";
const CUSTOM_VARIABLE_RECORD_NAME = 'CustomVariables_valueByName';
// Ecommerce reports use custom variables.
// We specifically set the limits high to get accurate Ecommerce reports
const MAX_ROWS_WHEN_ECOMMERCE = 50000;
/**
* @var DataArray
*/
protected $dataArray;
protected $maximumRowsInDataTableLevelZero;
protected $maximumRowsInSubDataTable;
protected $newEmptyRow;
function __construct($processor)
{
parent::__construct($processor);
if($processor->getParams()->getSite()->isEcommerceEnabled()) {
$this->maximumRowsInDataTableLevelZero = self::MAX_ROWS_WHEN_ECOMMERCE;
$this->maximumRowsInSubDataTable = self::MAX_ROWS_WHEN_ECOMMERCE;
} else {
$this->maximumRowsInDataTableLevelZero = Config::getInstance()->General['datatable_archiving_maximum_rows_custom_variables'];
$this->maximumRowsInSubDataTable = Config::getInstance()->General['datatable_archiving_maximum_rows_subtable_custom_variables'];
}
}
public function aggregateMultipleReports()
{
$this->getProcessor()->aggregateDataTableRecords(
self::CUSTOM_VARIABLE_RECORD_NAME, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable,
$columnToSort = Metrics::INDEX_NB_VISITS);
}
public function aggregateDayReport()
{
$this->dataArray = new DataArray();
$maxCustomVariables = CustomVariables::getMaxCustomVariables();
for ($i = 1; $i <= $maxCustomVariables; $i++) {
$this->aggregateCustomVariable($i);
}
$this->removeVisitsMetricsFromActionsAggregate();
$this->dataArray->enrichMetricsWithConversions();
$table = $this->dataArray->asDataTable();
$blob = $table->getSerialized(
$this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable,
$columnToSort = Metrics::INDEX_NB_VISITS
);
$this->getProcessor()->insertBlobRecord(self::CUSTOM_VARIABLE_RECORD_NAME, $blob);
}
protected function aggregateCustomVariable($slot)
{
$keyField = "custom_var_k" . $slot;
$valueField = "custom_var_v" . $slot;
$where = "%s.$keyField != ''";
$dimensions = array($keyField, $valueField);
$query = $this->getLogAggregator()->queryVisitsByDimension($dimensions, $where);
$this->aggregateFromVisits($query, $keyField, $valueField);
// IF we query Custom Variables scope "page" either: Product SKU, Product Name,
// then we also query the "Product page view" price which was possibly recorded.
$additionalSelects = false;
if (in_array($slot, array(\PiwikTracker::CVAR_INDEX_ECOMMERCE_ITEM_SKU, \PiwikTracker::CVAR_INDEX_ECOMMERCE_ITEM_NAME, \PiwikTracker::CVAR_INDEX_ECOMMERCE_ITEM_CATEGORY))) {
$additionalSelects = array($this->getSelectAveragePrice());
}
$query = $this->getLogAggregator()->queryActionsByDimension($dimensions, $where, $additionalSelects);
$this->aggregateFromActions($query, $keyField, $valueField);
$query = $this->getLogAggregator()->queryConversionsByDimension($dimensions, $where);
$this->aggregateFromConversions($query, $keyField, $valueField);
}
protected function getSelectAveragePrice()
{
$field = "custom_var_v" . \PiwikTracker::CVAR_INDEX_ECOMMERCE_ITEM_PRICE;
return LogAggregator::getSqlRevenue("AVG(log_link_visit_action." . $field . ")") . " as `" . Metrics::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED . "`";
}
protected function aggregateFromVisits($query, $keyField, $valueField)
{
while ($row = $query->fetch()) {
$key = $row[$keyField];
$value = $this->cleanCustomVarValue($row[$valueField]);
$this->dataArray->sumMetricsVisits($key, $row);
$this->dataArray->sumMetricsVisitsPivot($key, $value, $row);
}
}
protected function cleanCustomVarValue($value)
{
if (strlen($value)) {
return $value;
}
return self::LABEL_CUSTOM_VALUE_NOT_DEFINED;
}
protected function aggregateFromActions($query, $keyField, $valueField)
{
while ($row = $query->fetch()) {
$key = $row[$keyField];
$value = $this->cleanCustomVarValue($row[$valueField]);
$alreadyAggregated = $this->aggregateEcommerceCategories($key, $value, $row);
if (!$alreadyAggregated) {
$this->aggregateActionByKeyAndValue($key, $value, $row);
$this->dataArray->sumMetricsActions($key, $row);
}
}
}
/**
* @param string $key
* @param string $value
* @param $row
* @return bool True if the $row metrics were already added to the ->metrics
*/
protected function aggregateEcommerceCategories($key, $value, $row)
{
$ecommerceCategoriesAggregated = false;
if ($key == '_pkc'
&& $value[0] == '[' && $value[1] == '"'
) {
// In case categories were truncated, try closing the array
if (substr($value, -2) != '"]') {
$value .= '"]';
}
$decoded = @Common::json_decode($value);
if (is_array($decoded)) {
$count = 0;
foreach ($decoded as $category) {
if (empty($category)
|| $count >= GoalManager::MAXIMUM_PRODUCT_CATEGORIES
) {
continue;
}
$this->aggregateActionByKeyAndValue($key, $category, $row);
$ecommerceCategoriesAggregated = true;
$count++;
}
}
}
return $ecommerceCategoriesAggregated;
}
protected function aggregateActionByKeyAndValue($key, $value, $row)
{
$this->dataArray->sumMetricsActionsPivot($key, $value, $row);
if ($this->isReservedKey($key)) {
// Price tracking on Ecommerce product/category pages:
// the average is returned from the SQL query so the price is not "summed" like other metrics
$index = Metrics::INDEX_ECOMMERCE_ITEM_PRICE_VIEWED;
if (!empty($row[$index])) {
$this->dataArray->setRowColumnPivot($key, $value, $index, (float)$row[$index]);
}
}
}
protected static function isReservedKey($key)
{
return in_array($key, API::getReservedCustomVariableKeys());
}
protected function aggregateFromConversions($query, $keyField, $valueField)
{
if ($query === false) {
return;
}
while ($row = $query->fetch()) {
$key = $row[$keyField];
$value = $this->cleanCustomVarValue($row[$valueField]);
$this->dataArray->sumMetricsGoals($key, $row);
$this->dataArray->sumMetricsGoalsPivot($key, $value, $row);
}
}
protected function removeVisitsMetricsFromActionsAggregate()
{
$dataArray = & $this->dataArray->getDataArray();
foreach ($dataArray as $key => &$row) {
if (!self::isReservedKey($key)
&& DataArray::isRowActions($row)
) {
unset($row[Metrics::INDEX_NB_UNIQ_VISITORS]);
unset($row[Metrics::INDEX_NB_VISITS]);
}
}
}
}

View file

@ -0,0 +1,69 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\CustomVariables\Commands;
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;
/**
*/
class Info extends ConsoleCommand
{
protected function configure()
{
$this->setName('customvariables:info');
$this->setDescription('Get info about configured custom variables');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$maxVars = CustomVariables::getMaxCustomVariables();
if ($this->hasEverywhereSameAmountOfVariables()) {
$this->writeSuccessMessage($output, array(
'Your Piwik is configured for ' . $maxVars . ' custom variables.'
));
return;
}
$output->writeln('<error>There is a problem with your custom variables configuration:</error>');
$output->writeln('<error>Some database tables miss custom variables columns.</error>');
$output->writeln('');
$output->writeln('Your Piwik seems to be configured for ' . $maxVars . ' custom variables.');
$output->writeln('Executing "<comment>./console customvariables:set-max-custom-variables ' . $maxVars . '</comment>" might fix this issue.');
$output->writeln('If not check the following tables whether they have the same columns starting with <comment>custom_var_</comment>: ');
foreach (Model::getScopes() as $scope) {
$output->writeln(Common::prefixTable($scope));
}
}
private function hasEverywhereSameAmountOfVariables()
{
$indexesBefore = null;
foreach (Model::getScopes() as $scope) {
$model = new Model($scope);
$indexes = $model->getCustomVarIndexes();
if (is_null($indexesBefore)) {
$indexesBefore = $indexes;
} elseif ($indexes != $indexesBefore) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,210 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\CustomVariables\Commands;
use Piwik\Plugin\ConsoleCommand;
use Piwik\Tracker\Cache;
use Piwik\Plugins\CustomVariables\Model;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
*/
class SetNumberOfCustomVariables extends ConsoleCommand
{
/**
* @var \Symfony\Component\Console\Helper\ProgressHelper
*/
private $progress;
protected function configure()
{
$this->setName('customvariables:set-max-custom-variables');
$this->setDescription('Change the number of available custom variables');
$this->setHelp("Example:
./console customvariables:set-max-custom-variables 10
=> 10 custom variables will be available in total
");
$this->addArgument('maxCustomVars', InputArgument::REQUIRED, 'Set the number of max available custom variables');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$numVarsToSet = $this->getNumVariablesToSet($input);
$numChangesToPerform = $this->getNumberOfChangesToPerform($numVarsToSet);
if (0 === $numChangesToPerform) {
$this->writeSuccessMessage($output, array(
'Your Piwik is already configured for ' . $numVarsToSet . ' custom variables.'
));
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)) {
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();
$this->writeSuccessMessage($output, array(
'Your Piwik is now configured for ' . $numVarsToSet . ' custom variables.'
));
}
private function initProgress($numChangesToPerform, OutputInterface $output)
{
/** @var \Symfony\Component\Console\Helper\ProgressHelper $progress */
$progress = $this->getHelperSet()->get('progress');
$progress->start($output, $numChangesToPerform);
return $progress;
}
private function performChange($scope, $numVarsToSet, OutputInterface $output)
{
$model = new Model($scope);
$numCurrentVars = $model->getCurrentNumCustomVars();
$numDifference = $this->getAbsoluteDifference($numCurrentVars, $numVarsToSet);
if ($numVarsToSet > $numCurrentVars) {
$this->addCustomVariables($model, $numDifference, $output);
return;
}
$this->removeCustomVariables($model, $numDifference, $output);
}
private function getNumVariablesToSet(InputInterface $input)
{
$maxCustomVars = $input->getArgument('maxCustomVars');
if (!is_numeric($maxCustomVars)) {
throw new \InvalidArgumentException('The number of available custom variables has to be a number');
}
$maxCustomVars = (int) $maxCustomVars;
if ($maxCustomVars < 5) {
throw new \InvalidArgumentException('There has to be at least five custom variables');
}
return $maxCustomVars;
}
private function confirmChange(OutputInterface $output)
{
$output->writeln('');
$dialog = $this->getHelperSet()->get('dialog');
return $dialog->askConfirmation(
$output,
'<question>Are you sure you want to perform these actions? (y/N)</question>',
false
);
}
private function printChanges($scope, $numVarsToSet, OutputInterface $output)
{
$model = new Model($scope);
$scopeName = $model->getScopeName();
$highestIndex = $model->getHighestCustomVarIndex();
$numCurrentCustomVars = $model->getCurrentNumCustomVars();
$numVarsDifference = $this->getAbsoluteDifference($numCurrentCustomVars, $numVarsToSet);
$output->writeln('');
$output->writeln(sprintf('Scope "%s"', $scopeName));
if ($numVarsToSet > $numCurrentCustomVars) {
$indexes = $highestIndex + 1;
if (1 !== $numVarsDifference) {
$indexes .= ' - ' . ($highestIndex + $numVarsDifference);
}
$output->writeln(
sprintf('%s new custom variables having the index(es) %s will be ADDED', $numVarsDifference, $indexes)
);
} elseif ($numVarsToSet < $numCurrentCustomVars) {
$indexes = $highestIndex - $numVarsDifference + 1;
if (1 !== $numVarsDifference) {
$indexes .= ' - ' . $highestIndex;
}
$output->writeln(
sprintf("%s existing custom variables having the index(es) %s will be REMOVED.", $numVarsDifference, $indexes)
);
$output->writeln('<comment>This is an irreversible change</comment>');
}
}
private function getAbsoluteDifference($currentNumber, $numberToSet)
{
return abs($numberToSet - $currentNumber);
}
private function removeCustomVariables(Model $model, $numberOfVarsToRemove, OutputInterface $output)
{
for ($index = 0; $index < $numberOfVarsToRemove; $index++) {
$indexRemoved = $model->removeCustomVariable();
$this->progress->advance();
$output->writeln(' <info>Removed a variable in scope "' . $model->getScopeName() . '" having the index ' . $indexRemoved . '</info>');
}
}
private function addCustomVariables(Model $model, $numberOfVarsToAdd, OutputInterface $output)
{
for ($index = 0; $index < $numberOfVarsToAdd; $index++) {
$indexAdded = $model->addCustomVariable();
$this->progress->advance();
$output->writeln(' <info>Added a variable in scope "' . $model->getScopeName() . '" having the index ' . $indexAdded . '</info>');
}
}
private function getNumberOfChangesToPerform($numVarsToSet)
{
$numChangesToPerform = 0;
foreach (Model::getScopes() as $scope) {
$model = new Model($scope);
$numCurrentCustomVars = $model->getCurrentNumCustomVars();
$numChangesToPerform += $this->getAbsoluteDifference($numCurrentCustomVars, $numVarsToSet);
}
return $numChangesToPerform;
}
}

View file

@ -0,0 +1,36 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\CustomVariables;
use Piwik\Piwik;
use Piwik\View;
use Piwik\ViewDataTable\Factory;
/**
*/
class Controller extends \Piwik\Plugin\Controller
{
public function index()
{
return View::singleReport(
Piwik::translate('CustomVariables_CustomVariables'),
$this->getCustomVariables(true));
}
public function getCustomVariables()
{
return $this->renderReport(__FUNCTION__);
}
public function getCustomVariablesValuesFromNameId()
{
return $this->renderReport(__FUNCTION__);
}
}

View file

@ -0,0 +1,215 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
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;
/**
*/
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
*/
public function getListHooksRegistered()
{
$hooks = array(
'WidgetsList.addWidgets' => 'addWidgets',
'Menu.Reporting.addItems' => 'addMenus',
'Goals.getReportsWithGoalMetrics' => 'getReportsWithGoalMetrics',
'API.getReportMetadata' => 'getReportMetadata',
'API.getSegmentDimensionMetadata' => 'getSegmentsMetadata',
'ViewDataTable.configure' => 'configureViewDataTable'
);
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()
{
Model::install();
}
public function uninstall()
{
Model::uninstall();
}
/**
* There are also some hardcoded places in JavaScript
* @return int
*/
public static function getMaxLengthCustomVariables()
{
return 200;
}
public static function getMaxCustomVariables()
{
$cache = Cache::getCacheGeneral();
$cacheKey = 'CustomVariables.MaxNumCustomVariables';
if (!array_key_exists($cacheKey, $cache)) {
$maxCustomVar = 0;
foreach (Model::getScopes() as $scope) {
$model = new Model($scope);
$highestIndex = $model->getHighestCustomVarIndex();
if ($highestIndex > $maxCustomVar) {
$maxCustomVar = $highestIndex;
}
}
$cache[$cacheKey] = $maxCustomVar;
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();
for ($i = 1; $i <= $maxCustomVariables; $i++) {
$segments[] = array(
'type' => 'dimension',
'category' => 'CustomVariables_CustomVariables',
'name' => Piwik::translate('CustomVariables_ColumnCustomVariableName') . ' ' . $i
. ' (' . Piwik::translate('CustomVariables_ScopeVisit') . ')',
'segment' => 'customVariableName' . $i,
'sqlSegment' => 'log_visit.custom_var_k' . $i,
);
$segments[] = array(
'type' => 'dimension',
'category' => 'CustomVariables_CustomVariables',
'name' => Piwik::translate('CustomVariables_ColumnCustomVariableValue') . ' ' . $i
. ' (' . Piwik::translate('CustomVariables_ScopeVisit') . ')',
'segment' => 'customVariableValue' . $i,
'sqlSegment' => 'log_visit.custom_var_v' . $i,
);
$segments[] = array(
'type' => 'dimension',
'category' => 'CustomVariables_CustomVariables',
'name' => Piwik::translate('CustomVariables_ColumnCustomVariableName') . ' ' . $i
. ' (' . Piwik::translate('CustomVariables_ScopePage') . ')',
'segment' => 'customVariablePageName' . $i,
'sqlSegment' => 'log_link_visit_action.custom_var_k' . $i,
);
$segments[] = array(
'type' => 'dimension',
'category' => 'CustomVariables_CustomVariables',
'name' => Piwik::translate('CustomVariables_ColumnCustomVariableValue') . ' ' . $i
. ' (' . Piwik::translate('CustomVariables_ScopePage') . ')',
'segment' => 'customVariablePageValue' . $i,
'sqlSegment' => 'log_link_visit_action.custom_var_v' . $i,
);
}
}
/**
* Adds Goal dimensions, so that the dimensions are displayed in the UI Goal Overview page
*/
public function getReportsWithGoalMetrics(&$dimensions)
{
$dimensions[] = array('category' => Piwik::translate('General_Visit'),
'name' => Piwik::translate('CustomVariables_CustomVariables'),
'module' => 'CustomVariables',
'action' => 'getCustomVariables',
);
}
public function configureViewDataTable(ViewDataTable $view)
{
switch ($view->requestConfig->apiMethodToRequestDataTable) {
case 'CustomVariables.getCustomVariables':
$this->configureViewForGetCustomVariables($view);
break;
case 'CustomVariables.getCustomVariablesValuesFromNameId':
$this->configureViewForGetCustomVariablesValuesFromNameId($view);
break;
}
}
private function configureViewForGetCustomVariables(ViewDataTable $view)
{
$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';
}
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,186 @@
<?php
/**
* Piwik - Open source web analytics
*
* @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\DataTable;
use Piwik\Db;
use Piwik\Log;
class Model
{
const SCOPE_PAGE = 'log_link_visit_action';
const SCOPE_VISIT = 'log_visit';
const SCOPE_CONVERSION = 'log_conversion';
private $scope = null;
public function __construct($scope)
{
if (empty($scope) || !in_array($scope, $this->getScopes())) {
throw new \Exception('Invalid custom variable scope');
}
$this->scope = $scope;
}
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';
}
}
/**
* @see getHighestCustomVarIndex()
* @return int
*/
public function getCurrentNumCustomVars()
{
$indexes = $this->getCustomVarIndexes();
return count($indexes);
}
/**
* result of getHighestCustomVarIndex() can be different to getCurrentNumCustomVars() in case there are some missing
* custom variable indexes. For instance in case of manual changes on the DB
*
* custom_var_v1
* custom_var_v2
* custom_var_v4
*
* getHighestCustomVarIndex() -> returns 4
* getCurrentNumCustomVars() -> returns 3
*
* @return int
*/
public function getHighestCustomVarIndex()
{
$indexes = $this->getCustomVarIndexes();
if (empty($indexes)) {
return 0;
}
return max($indexes);
}
public function getCustomVarIndexes()
{
$columns = $this->getCustomVarColumnNames();
if (empty($columns)) {
return array();
}
$indexes = array_map(function ($column) {
return Model::getCustomVariableIndexFromFieldName($column);
}, $columns);
return array_values(array_unique($indexes));
}
private function getCustomVarColumnNames()
{
$dbTable = $this->getDbTableName();
$columns = Db::getColumnNamesFromTable($dbTable);
$customVarColumns = array_filter($columns, function ($column) {
return false !== strpos($column, 'custom_var_');
});
return $customVarColumns;
}
public function removeCustomVariable()
{
$dbTable = $this->getDbTableName();
$index = $this->getHighestCustomVarIndex();
if ($index < 1) {
return null;
}
Db::exec(sprintf('ALTER TABLE %s ', $dbTable)
. sprintf('DROP COLUMN custom_var_k%d,', $index)
. sprintf('DROP COLUMN custom_var_v%d;', $index));
return $index;
}
public function addCustomVariable()
{
$dbTable = $this->getDbTableName();
$index = $this->getHighestCustomVarIndex() + 1;
$maxLen = CustomVariables::getMaxLengthCustomVariables();
Db::exec(sprintf('ALTER TABLE %s ', $dbTable)
. 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);
if (is_numeric($onlyNumber)) {
return (int) $onlyNumber;
}
}
public static function getScopes()
{
return array(self::SCOPE_PAGE, self::SCOPE_VISIT, self::SCOPE_CONVERSION);
}
public static function install()
{
foreach (self::getScopes() as $scope) {
$model = new Model($scope);
try {
$maxCustomVars = 5;
$customVarsToAdd = $maxCustomVars - $model->getCurrentNumCustomVars();
for ($index = 0; $index < $customVarsToAdd; $index++) {
$model->addCustomVariable();
}
} catch (\Exception $e) {
Log::warning('Failed to add custom variable: ' . $e->getMessage());
}
}
}
public static function uninstall()
{
foreach (self::getScopes() as $scope) {
$model = new Model($scope);
while ($model->getHighestCustomVarIndex()) {
$model->removeCustomVariable();
}
}
}
}