hide map for Character groups Quest Stations when there are no stations
This commit is contained in:
commit
df14dfafc3
4371 changed files with 1220224 additions and 0 deletions
109
www/analytics/plugins/CustomVariables/API.php
Normal file
109
www/analytics/plugins/CustomVariables/API.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
220
www/analytics/plugins/CustomVariables/Archiver.php
Normal file
220
www/analytics/plugins/CustomVariables/Archiver.php
Normal 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
69
www/analytics/plugins/CustomVariables/Commands/Info.php
Normal file
69
www/analytics/plugins/CustomVariables/Commands/Info.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
36
www/analytics/plugins/CustomVariables/Controller.php
Normal file
36
www/analytics/plugins/CustomVariables/Controller.php
Normal 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__);
|
||||
}
|
||||
}
|
||||
|
||||
215
www/analytics/plugins/CustomVariables/CustomVariables.php
Normal file
215
www/analytics/plugins/CustomVariables/CustomVariables.php
Normal 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';
|
||||
}
|
||||
}
|
||||
186
www/analytics/plugins/CustomVariables/Model.php
Normal file
186
www/analytics/plugins/CustomVariables/Model.php
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue