PDF rausgenommen
This commit is contained in:
@ -0,0 +1,188 @@
|
||||
<?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\CoreAdminHome\Model;
|
||||
|
||||
use Piwik\Common;
|
||||
use Piwik\Container\StaticContainer;
|
||||
use Piwik\DataAccess\TableMetadata;
|
||||
use Piwik\Db;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Provides methods to find duplicate actions and fix duplicate action references in tables
|
||||
* that reference log_action rows.
|
||||
*/
|
||||
class DuplicateActionRemover
|
||||
{
|
||||
/**
|
||||
* The tables that contain idaction reference columns.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public static $tablesWithIdActionColumns = array(
|
||||
'log_link_visit_action',
|
||||
'log_conversion',
|
||||
'log_conversion_item'
|
||||
);
|
||||
|
||||
/**
|
||||
* DAO used to get idaction column names in tables that reference log_action rows.
|
||||
*
|
||||
* @var TableMetadata
|
||||
*/
|
||||
private $tableMetadataAccess;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* List of idaction columns in each table in $tablesWithIdActionColumns. idaction
|
||||
* columns are table columns with the string `"idaction"` in them.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $idactionColumns = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param TableMetadata $tableMetadataAccess
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function __construct(TableMetadata $tableMetadataAccess = null, LoggerInterface $logger = null)
|
||||
{
|
||||
$this->tableMetadataAccess = $tableMetadataAccess ?: new TableMetadata();
|
||||
$this->logger = $logger ?: StaticContainer::get('Psr\Log\LoggerInterface');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of all duplicate actions in the log_action table by name and the lowest action ID.
|
||||
* The duplicate actions are returned with each action.
|
||||
*
|
||||
* @return array Contains the following elements:
|
||||
*
|
||||
* * **name**: The action's name.
|
||||
* * **idaction**: The action's ID.
|
||||
* * **duplicateIdActions**: An array of duplicate action IDs.
|
||||
*/
|
||||
public function getDuplicateIdActions()
|
||||
{
|
||||
$sql = "SELECT name, COUNT(*) AS count, GROUP_CONCAT(idaction ORDER BY idaction ASC SEPARATOR ',') as idactions
|
||||
FROM " . Common::prefixTable('log_action') . "
|
||||
GROUP BY name, hash, type HAVING count > 1";
|
||||
|
||||
$result = array();
|
||||
foreach (Db::fetchAll($sql) as $row) {
|
||||
$dupeInfo = array('name' => $row['name']);
|
||||
|
||||
$idActions = explode(",", $row['idactions']);
|
||||
$dupeInfo['idaction'] = array_shift($idActions);
|
||||
$dupeInfo['duplicateIdActions'] = $idActions;
|
||||
|
||||
$result[] = $dupeInfo;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes one SQL statement that sets all idaction columns in a table to a single value, if the
|
||||
* values of those columns are in the specified set (`$duplicateIdActions`).
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* The SQL will look like:
|
||||
*
|
||||
* UPDATE $table SET
|
||||
* col1 = IF((col1 IN ($duplicateIdActions)), $realIdAction, col1),
|
||||
* col2 = IF((col2 IN ($duplicateIdActions)), $realIdAction, col2),
|
||||
* ...
|
||||
* WHERE col1 IN ($duplicateIdActions) OR col2 IN ($duplicateIdActions) OR ...
|
||||
*
|
||||
* @param string $table
|
||||
* @param int $realIdAction The idaction to set column values to.
|
||||
* @param int[] $duplicateIdActions The idaction values that should be changed.
|
||||
*/
|
||||
public function fixDuplicateActionsInTable($table, $realIdAction, $duplicateIdActions)
|
||||
{
|
||||
$idactionColumns = $this->getIdActionTableColumnsFromMetadata();
|
||||
$idactionColumns = array_values($idactionColumns[$table]);
|
||||
$table = Common::prefixTable($table);
|
||||
|
||||
$inFromIdsExpression = $this->getInFromIdsExpression($duplicateIdActions);
|
||||
$setExpression = "%1\$s = IF(($inFromIdsExpression), $realIdAction, %1\$s)";
|
||||
|
||||
$sql = "UPDATE $table SET\n";
|
||||
foreach ($idactionColumns as $index => $column) {
|
||||
if ($index != 0) {
|
||||
$sql .= ",\n";
|
||||
}
|
||||
$sql .= sprintf($setExpression, $column);
|
||||
}
|
||||
$sql .= $this->getWhereToGetRowsUsingDuplicateActions($idactionColumns, $duplicateIdActions);
|
||||
|
||||
Db::query($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server time and idsite of rows in a log table that reference at least one action
|
||||
* in a set.
|
||||
*
|
||||
* @param string $table
|
||||
* @param int[] $duplicateIdActions
|
||||
* @return array with two elements **idsite** and **server_time**. idsite is the site ID and server_time
|
||||
* is the date of the log.
|
||||
*/
|
||||
public function getSitesAndDatesOfRowsUsingDuplicates($table, $duplicateIdActions)
|
||||
{
|
||||
$idactionColumns = $this->getIdActionTableColumnsFromMetadata();
|
||||
$idactionColumns = array_values($idactionColumns[$table]);
|
||||
$table = Common::prefixTable($table);
|
||||
|
||||
$sql = "SELECT idsite, DATE(server_time) as server_time FROM $table ";
|
||||
$sql .= $this->getWhereToGetRowsUsingDuplicateActions($idactionColumns, $duplicateIdActions);
|
||||
return Db::fetchAll($sql);
|
||||
}
|
||||
|
||||
private function getIdActionTableColumnsFromMetadata()
|
||||
{
|
||||
if ($this->idactionColumns === null) {
|
||||
$this->idactionColumns = array();
|
||||
foreach (self::$tablesWithIdActionColumns as $table) {
|
||||
$columns = $this->tableMetadataAccess->getIdActionColumnNames(Common::prefixTable($table));
|
||||
|
||||
$this->logger->debug("Found following idactions in {table}: {columns}", array(
|
||||
'table' => $table,
|
||||
'columns' => implode(',', $columns)
|
||||
));
|
||||
|
||||
$this->idactionColumns[$table] = $columns;
|
||||
}
|
||||
}
|
||||
return $this->idactionColumns;
|
||||
}
|
||||
|
||||
private function getWhereToGetRowsUsingDuplicateActions($idactionColumns, $fromIdActions)
|
||||
{
|
||||
$sql = "WHERE ";
|
||||
foreach ($idactionColumns as $index => $column) {
|
||||
if ($index != 0) {
|
||||
$sql .= "OR ";
|
||||
}
|
||||
|
||||
$sql .= sprintf($this->getInFromIdsExpression($fromIdActions), $column) . " ";
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
private function getInFromIdsExpression($fromIdActions)
|
||||
{
|
||||
return "%1\$s IN (" . implode(',', $fromIdActions) . ")";
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user