From 764b3b80bef6e54c08b4875c97034fcfacd1d55c Mon Sep 17 00:00:00 2001
From: Thomas Steur <thomas.steur@gmail.com>
Date: Tue, 21 Jul 2015 08:51:16 +0000
Subject: [PATCH] refs #8304 make sure to not uninstall a dimension if another
 plugin defines the same, make sure to correctly mark the dimension as
 uninstalled

---
 core/Columns/Dimension.php                    |  2 +-
 core/Columns/Updater.php                      |  6 +--
 core/Plugin/Dimension/ActionDimension.php     |  2 +
 core/Plugin/Dimension/ConversionDimension.php |  2 +
 core/Plugin/Dimension/VisitDimension.php      |  2 +
 core/Plugin/Manager.php                       | 49 ++++++++++++++++---
 core/Updater.php                              | 15 ++++++
 7 files changed, 66 insertions(+), 12 deletions(-)

diff --git a/core/Columns/Dimension.php b/core/Columns/Dimension.php
index 8da3822fa9..c89ae637a5 100644
--- a/core/Columns/Dimension.php
+++ b/core/Columns/Dimension.php
@@ -142,7 +142,7 @@ abstract class Dimension
 
     /**
      * Returns a unique string ID for this dimension. The ID is built using the namespaced class name
-     * of the dimension, but is modified to be more human readable
+     * of the dimension, but is modified to be more human readable.
      *
      * @return string eg, `"Referrers.Keywords"`
      * @throws Exception if the plugin and simple class name of this instance cannot be determined.
diff --git a/core/Columns/Updater.php b/core/Columns/Updater.php
index f6121165bb..a29ed16330 100644
--- a/core/Columns/Updater.php
+++ b/core/Columns/Updater.php
@@ -163,15 +163,15 @@ class Updater extends \Piwik\Updates
         $conversionColumns = DbHelper::getTableColumns(Common::prefixTable('log_conversion'));
 
         foreach ($this->visitDimensions as $dimension) {
-            $versions = $this->mixinVersions($updater, $dimension, 'log_visit.', $visitColumns, $versions);
+            $versions = $this->mixinVersions($updater, $dimension, VisitDimension::INSTALLER_PREFIX, $visitColumns, $versions);
         }
 
         foreach ($this->actionDimensions as $dimension) {
-            $versions = $this->mixinVersions($updater, $dimension, 'log_link_visit_action.', $actionColumns, $versions);
+            $versions = $this->mixinVersions($updater, $dimension, ActionDimension::INSTALLER_PREFIX, $actionColumns, $versions);
         }
 
         foreach ($this->conversionDimensions as $dimension) {
-            $versions = $this->mixinVersions($updater, $dimension, 'log_conversion.', $conversionColumns, $versions);
+            $versions = $this->mixinVersions($updater, $dimension, ConversionDimension::INSTALLER_PREFIX, $conversionColumns, $versions);
         }
 
         return $versions;
diff --git a/core/Plugin/Dimension/ActionDimension.php b/core/Plugin/Dimension/ActionDimension.php
index 3c697641a3..ce8a1eeda2 100644
--- a/core/Plugin/Dimension/ActionDimension.php
+++ b/core/Plugin/Dimension/ActionDimension.php
@@ -36,6 +36,8 @@ use Exception;
  */
 abstract class ActionDimension extends Dimension
 {
+    const INSTALLER_PREFIX = 'log_link_visit_action.';
+
     private $tableName = 'log_link_visit_action';
 
     /**
diff --git a/core/Plugin/Dimension/ConversionDimension.php b/core/Plugin/Dimension/ConversionDimension.php
index e20f1eeeaf..ff1bff55ae 100644
--- a/core/Plugin/Dimension/ConversionDimension.php
+++ b/core/Plugin/Dimension/ConversionDimension.php
@@ -38,6 +38,8 @@ use Exception;
  */
 abstract class ConversionDimension extends Dimension
 {
+    const INSTALLER_PREFIX = 'log_conversion.';
+
     private $tableName = 'log_conversion';
 
     /**
diff --git a/core/Plugin/Dimension/VisitDimension.php b/core/Plugin/Dimension/VisitDimension.php
index b93ca041b6..48bcf70516 100644
--- a/core/Plugin/Dimension/VisitDimension.php
+++ b/core/Plugin/Dimension/VisitDimension.php
@@ -37,6 +37,8 @@ use Exception;
  */
 abstract class VisitDimension extends Dimension
 {
+    const INSTALLER_PREFIX = 'log_visit.';
+
     private $tableName = 'log_visit';
 
     /**
diff --git a/core/Plugin/Manager.php b/core/Plugin/Manager.php
index 25434468d1..ff4c3553dc 100644
--- a/core/Plugin/Manager.php
+++ b/core/Plugin/Manager.php
@@ -1219,34 +1219,66 @@ class Manager
         }
 
         try {
+            $visitDimensions = VisitDimension::getAllDimensions();
+
             foreach (VisitDimension::getDimensions($plugin) as $dimension) {
-                $this->uninstallDimension($dimension);
+                $this->uninstallDimension(VisitDimension::INSTALLER_PREFIX, $dimension, $visitDimensions);
             }
         } catch (\Exception $e) {
         }
 
         try {
+            $actionDimensions = ActionDimension::getAllDimensions();
+
             foreach (ActionDimension::getDimensions($plugin) as $dimension) {
-                $this->uninstallDimension($dimension);
+                $this->uninstallDimension(ActionDimension::INSTALLER_PREFIX, $dimension, $actionDimensions);
             }
         } catch (\Exception $e) {
         }
 
         try {
+            $conversionDimensions = ConversionDimension::getAllDimensions();
+
             foreach (ConversionDimension::getDimensions($plugin) as $dimension) {
-                $this->uninstallDimension($dimension);
+                $this->uninstallDimension(ConversionDimension::INSTALLER_PREFIX, $dimension, $conversionDimensions);
             }
         } catch (\Exception $e) {
         }
     }
 
     /**
+     * @param VisitDimension|ActionDimension|ConversionDimension $dimension
+     * @param VisitDimension[]|ActionDimension[]|ConversionDimension[] $allDimensions
+     * @return bool
+     */
+    private function doesAnotherPluginDefineSameColumnWithDbEntry($dimension, $allDimensions)
+    {
+        $module = $dimension->getModule();
+        $columnName = $dimension->getColumnName();
+
+        foreach ($allDimensions as $dim) {
+            if ($dim->getColumnName() === $columnName &&
+                $dim->hasColumnType() &&
+                $dim->getModule() !== $module) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @param string $prefix column installer prefix
      * @param ConversionDimension|VisitDimension|ActionDimension $dimension
+     * @param VisitDimension[]|ActionDimension[]|ConversionDimension[] $allDimensions
      */
-    private function uninstallDimension(Dimension $dimension)
+    private function uninstallDimension($prefix, Dimension $dimension, $allDimensions)
     {
-        $dimension->uninstall();
-        Option::delete('version_' . $dimension->getVersion());
+        if (!$this->doesAnotherPluginDefineSameColumnWithDbEntry($dimension, $allDimensions)) {
+            $dimension->uninstall();
+
+            $this->removeInstalledVersionFromOptionTable($prefix . $dimension->getColumnName());
+        }
     }
 
     /**
@@ -1259,9 +1291,10 @@ class Manager
         return in_array($pluginName, $pluginsInstalled);
     }
 
-    private function removeInstalledVersionFromOptionTable($version)
+    private function removeInstalledVersionFromOptionTable($name)
     {
-        Option::delete('version_' . $version);
+        $updater = new Updater();
+        $updater->markComponentSuccessfullyUninstalled($name);
     }
 
     private function makeSureOnlyActivatedPluginsAreLoaded()
diff --git a/core/Updater.php b/core/Updater.php
index 9190320fa7..90c8c6839c 100644
--- a/core/Updater.php
+++ b/core/Updater.php
@@ -90,6 +90,21 @@ class Updater
         }
     }
 
+    /**
+     * Marks a component as successfully uninstalled. Deletes an option
+     * that looks like `"version_$componentName"`.
+     *
+     * @param string $name The component name. Eg, a plugin name, `'core'` or dimension column name.
+     */
+    public function markComponentSuccessfullyUninstalled($name)
+    {
+        try {
+            Option::delete(self::getNameInOptionTable($name));
+        } catch (\Exception $e) {
+            // case when the option table is not yet created (before 0.2.10)
+        }
+    }
+
     /**
      * Returns the currently installed version of a Piwik component.
      *
-- 
GitLab