mirror of
https://github.com/VTECRM/vtenext.git
synced 2026-02-26 16:18:47 +00:00
537 lines
15 KiB
Plaintext
537 lines
15 KiB
Plaintext
<?php
|
|
/*************************************
|
|
* SPDX-FileCopyrightText: 2009-2020 Vtenext S.r.l. <info@vtenext.com>
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
************************************/
|
|
|
|
/* crmv@64542 */
|
|
|
|
/*@ DEL
|
|
|
|
This is a template file for the ModuleMaker
|
|
There are some special values in this file:
|
|
|
|
1. Any comment starting with /*@ is treated as a special comment and the next characters
|
|
on that line specifies a command:
|
|
DEL: remove all the comment until the closing tag (which has the @ sign as well)
|
|
REPLACE: the comment is replaced with a standard comment, with some other text inside
|
|
|
|
2. All the variables that begin with $TPL_ are replaced with other values/variables
|
|
|
|
@*/
|
|
|
|
/* Automatic installation script */
|
|
/* This file must be placed in the VTEROOT/storage/custom_modules folder */
|
|
|
|
// security check
|
|
if (php_sapi_name() != "cli" && !defined('MODULEMAKERSCRIPT')) {
|
|
throw new UninstallException("You are not allowed to invoke this script in this way!");
|
|
}
|
|
|
|
$configInc = '../../config.inc.php';
|
|
if (!is_readable($configInc)) throw new UninstallException("File $configInc not found. Ensure this file is in the storage/custom_modules folder");
|
|
|
|
/* Includes */
|
|
require($configInc);
|
|
chdir($root_directory);
|
|
require('vteversion.php'); // crmv@181168
|
|
|
|
require_once('include/utils/utils.php');
|
|
require_once('modules/Update/Update.php');
|
|
require_once('vtlib/Vtecrm/Utils.php');
|
|
require_once('vtlib/Vtecrm/Field.php');
|
|
require_once('vtlib/Vtecrm/Module.php');
|
|
|
|
/* Globals */
|
|
global $adb, $table_prefix, $vtlib_Utils_Log, $current_user;
|
|
$vtlib_Utils_Log = true;
|
|
|
|
// missing current_user, when invoking from CLI
|
|
if (!isset($current_user)) {
|
|
$current_user = CRMEntity::getInstance('Users');
|
|
$current_user->id = 1;
|
|
}
|
|
|
|
/* Script class */
|
|
$MMS = new ModuleMakerScriptUninstall();
|
|
|
|
|
|
/* Basic variables */
|
|
$module_name = $TPL_MODULENAME;
|
|
|
|
$module_dest_dir = "modules/$module_name";
|
|
|
|
|
|
/* Module variables */
|
|
|
|
// other fields to remove
|
|
$module_other_fields = $TPL_OTHERFIELDS;
|
|
|
|
// relations NtoN to remove
|
|
$module_relations = $TPL_RELATIONS;
|
|
|
|
// relations 1toN to existing fields to remove
|
|
$module_addrelations = $TPL_ADDRELATIONS;
|
|
|
|
// labels to remove
|
|
$labels = $TPL_LANGUAGES;
|
|
|
|
|
|
// ----------------- SCRIPT START -------------------
|
|
|
|
|
|
// check destination directory
|
|
if (!is_writable('modules')) {
|
|
throw new InstallException("The modules folder is not writable, please fix the permissions");
|
|
}
|
|
|
|
// instance to the module
|
|
$newModule = Vtecrm_Module::getInstance($module_name);
|
|
|
|
|
|
// remove other labels
|
|
if (is_array($labels)) {
|
|
foreach ($labels as $module=>$modlang) {
|
|
foreach ($modlang as $lang=>$translist) {
|
|
foreach ($translist as $label=>$translabel) {
|
|
SDK::deleteLanguageEntry($module, $lang, $label);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// relations NtoN (couple of related lists)
|
|
if (is_array($module_relations)) {
|
|
foreach ($module_relations as $rel) {
|
|
$relinst = Vtecrm_Module::getInstance($rel['module']);
|
|
if ($relinst) {
|
|
if (!empty($rel['function'])) {
|
|
$func = $rel['function'];
|
|
} elseif ($rel['module'] == 'Messages') {
|
|
$func = 'get_messages_list';
|
|
} elseif ($rel['module'] == 'Documents') {
|
|
$func = 'get_attachments';
|
|
} else {
|
|
$func = 'get_related_list';
|
|
}
|
|
// check the inverse relation function
|
|
if (!empty($rel['reverse_function'])) {
|
|
$func2 = $rel['reverse_function'];
|
|
} elseif ($rel['module'] == 'Documents') {
|
|
$func2 = 'get_documents_dependents_list';
|
|
} else {
|
|
$func2 = $func;
|
|
}
|
|
$relinst->unsetRelatedList($newModule, $module_name, $func2);
|
|
if ($newModule) $newModule->unsetRelatedList($relinst, $rel['module'], $func);
|
|
}
|
|
}
|
|
}
|
|
|
|
// relations 1toN with fields not to remove
|
|
if (is_array($module_addrelations)) {
|
|
foreach ($module_addrelations as $rel) {
|
|
$relinst = Vtecrm_Module::getInstance($rel['module']);
|
|
if ($relinst) {
|
|
$label = $rel['module'];
|
|
if (!empty($rel['function'])) {
|
|
$func = $rel['function'];
|
|
} elseif ($rel['module'] == 'Calendar') {
|
|
$func = 'get_activities';
|
|
} else {
|
|
$func = 'get_dependents_list';
|
|
}
|
|
if ($func == 'get_activities') {
|
|
$label = 'Activities';
|
|
}
|
|
if ($newModule) $newModule->unsetRelatedList($relinst, $label, $func);
|
|
if ($rel['field']) {
|
|
$field = @Vtecrm_Field::getInstance($rel['field'], $relinst);
|
|
if ($field) {
|
|
$field->unsetRelatedModules(array($module_name));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove other modules fields
|
|
if (is_array($module_other_fields)) {
|
|
foreach ($module_other_fields as $field) {
|
|
$name = $field['name'];
|
|
$mod = $field['module'];
|
|
$modInst = Vtecrm_Module::getInstance($mod);
|
|
if (empty($modInst)) {
|
|
$MMS->warn("The module $mod was not found while removing the field $name");
|
|
continue;
|
|
}
|
|
$field = @Vtecrm_Field::getInstance($name, $modInst);
|
|
if ($field) {
|
|
$field->delete();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// now delete all
|
|
$r = $MMS->deleteModuleData($module_name);
|
|
if (!$r) throw new UninstallException("Error during module removal");
|
|
|
|
$r = $MMS->deleteModuleFiles($module_name);
|
|
if (!$r) throw new UninstallException("Error during module files removal");
|
|
|
|
// and just to be sure, regenerate the tabdata
|
|
create_tab_data_file();
|
|
|
|
// crmv@104956
|
|
// clear some caches
|
|
if (class_exists('Cache')) {
|
|
$cache = Cache::getInstance('getQuickCreateModules');
|
|
if ($cache) $cache->clear();
|
|
}
|
|
// crmv@104956e
|
|
|
|
|
|
// ----------------------------------- CLASSES ---------------------------------------
|
|
|
|
class UninstallException extends Exception { }
|
|
|
|
// some useful functions for the uninstall
|
|
class ModuleMakerScriptUninstall {
|
|
|
|
public $enableLog = true;
|
|
protected static $dbtables = array(); // crmv@167431
|
|
|
|
public function warn($s) {
|
|
return $this->log('[WARNING] '.$s);
|
|
}
|
|
|
|
public function log($s) {
|
|
if ($this->enableLog) echo $s."\n";
|
|
}
|
|
|
|
/**
|
|
* Remove ALL the record and metadata for the specified custom module
|
|
*/
|
|
public function deleteModuleData($modname) {
|
|
global $adb, $table_prefix;
|
|
|
|
// crmv@108984
|
|
$module = Vtecrm_Module::getInstance($modname);
|
|
if ($module) {
|
|
$tabid = $module->id;
|
|
} else {
|
|
$tabid = getTabid($modname);
|
|
}
|
|
|
|
// crmv@69568
|
|
// remove some accessory data
|
|
$this->deleteReports($modname);
|
|
$this->deleteWorkflows($modname);
|
|
$this->deletePicklists($modname);
|
|
// crmv@69568e
|
|
|
|
// remove the module tables
|
|
$this->dropModuleTables($modname);
|
|
|
|
// delete module with vtlib
|
|
if ($module) $module->__delete();
|
|
// crmv@108984e
|
|
|
|
// removes all the rows with references to this module
|
|
if ($tabid > 0) {
|
|
$this->deleteRowsWithColumnValue('tabid', $tabid, true);
|
|
}
|
|
$this->deleteRowsWithColumnValue('entitytype', $modname, false);
|
|
$this->deleteRowsWithColumnValue('entity_type', $modname, false);
|
|
$this->deleteRowsWithColumnValue('setype', $modname, false);
|
|
$this->deleteRowsWithColumnValue('module', $modname, false);
|
|
$this->deleteRowsWithColumnValue('relmodule', $modname, false);
|
|
$this->deleteRowsWithColumnValue('semodule', $modname, false);
|
|
// crmv@80117
|
|
if (Vtecrm_Utils::CheckTable($table_prefix.'_fieldformulas')) {
|
|
$adb->pquery("DELETE FROM {$table_prefix}_fieldformulas WHERE modulename = ?", array($modname));
|
|
}
|
|
// crmv@80117e
|
|
//crmv@85638 - these shouldn't be necessary, but sometimes the deleteRowsWithColumnValue doesn't work (?)
|
|
if ($tabid > 0) {
|
|
$adb->pquery("DELETE FROM {$table_prefix}_profile2standardperm WHERE tabid = ?", array($tabid));
|
|
$adb->pquery("DELETE FROM {$table_prefix}_org_share_action2tab WHERE tabid = ?", array($tabid));
|
|
}
|
|
//crmv@85638e
|
|
|
|
// TODO: maybe there are other tables/columns?
|
|
|
|
return true;
|
|
}
|
|
|
|
// crmv@69568
|
|
|
|
//crmv@95610
|
|
// delete all the workflows with this primary module
|
|
protected function deleteWorkflows($modname) {
|
|
global $adb, $table_prefix;
|
|
|
|
require_once("modules/com_workflow/VTWorkflowApplication.inc");
|
|
require_once("modules/com_workflow/VTWorkflowManager.inc");
|
|
require_once("modules/com_workflow/VTWorkflowUtils.php");
|
|
|
|
$this->log('Deleting all workflows...');
|
|
|
|
$res = $adb->pquery("SELECT w.workflow_id
|
|
FROM com_{$table_prefix}_workflows w
|
|
WHERE w.module_name = ?", array($modname));
|
|
if ($res && $adb->num_rows($res) > 0) {
|
|
$wm = new VTWorkflowManager($adb);
|
|
while ($row = $adb->FetchByAssoc($res, -1, false)) {
|
|
$id = intval($row['workflow_id']);
|
|
if ($id > 0) $wm->delete($id);
|
|
}
|
|
}
|
|
}
|
|
//crmv@95610e
|
|
|
|
// crmv@99794
|
|
// delete all the reports with this primary module
|
|
protected function deleteReports($modname) {
|
|
global $adb, $table_prefix;
|
|
|
|
require_once('modules/Reports/Reports.php');
|
|
$reports = Reports::getInstance();
|
|
|
|
$this->log('Deleting all reports...');
|
|
|
|
$res = $adb->pquery("SELECT r.reportid
|
|
FROM {$table_prefix}_report r
|
|
INNER JOIN {$table_prefix}_reportconfig rc ON rc.reportid = r.reportid
|
|
WHERE rc.module = ?", array($modname));
|
|
if ($res && $adb->num_rows($res) > 0) {
|
|
while ($row = $adb->FetchByAssoc($res, -1, false)) {
|
|
$id = intval($row['reportid']);
|
|
if ($id > 0) $reports->deleteReport($id);
|
|
}
|
|
}
|
|
}
|
|
// crmv@99794e
|
|
|
|
protected function deletePicklists($modname) {
|
|
global $adb, $table_prefix;
|
|
|
|
$this->log('Dropping all picklist values and tables...');
|
|
|
|
// search for picklist fields and remove their tables
|
|
$res = $adb->pquery("SELECT fieldid, fieldname, p.picklistid
|
|
FROM {$table_prefix}_field f
|
|
INNER JOIN {$table_prefix}_tab t ON t.tabid = f.tabid
|
|
LEFT JOIN {$table_prefix}_picklist p ON p.name = f.fieldname
|
|
WHERE t.name = ? AND f.uitype IN (?,?,?,?) ", array($modname, 15, 16, 1015, 300));
|
|
if ($res && $adb->num_rows($res) > 0) {
|
|
while ($row = $adb->FetchByAssoc($res, -1, false)) {
|
|
$fieldid = $row['fieldid'];
|
|
$pickid = intval($row['picklistid']);
|
|
// delete the values
|
|
if ($pickid > 0) {
|
|
$adb->pquery("DELETE FROM {$table_prefix}_picklist WHERE picklistid = ?", array($pickid));
|
|
$adb->pquery("DELETE FROM {$table_prefix}_role2picklist WHERE picklistid = ?", array($pickid));
|
|
}
|
|
|
|
// drop the tables
|
|
$tab = $table_prefix.'_'.$row['fieldname'];
|
|
if (Vtecrm_Utils::CheckTable($tab)) {
|
|
$dropq = $adb->datadict->DropTableSQL($tab);
|
|
$adb->datadict->ExecuteSQLArray($dropq);
|
|
}
|
|
$tab_seq = $table_prefix.'_'.$row['fieldname'].'_seq';
|
|
if (Vtecrm_Utils::CheckTable($tab_seq)) {
|
|
$dropq = $adb->datadict->DropTableSQL($tab_seq);
|
|
$adb->datadict->ExecuteSQLArray($dropq);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// crmv@69568e
|
|
|
|
protected function dropModuleTables($modname) {
|
|
global $adb, $table_prefix;
|
|
|
|
$this->log('Dropping module tables...');
|
|
|
|
$tables = array();
|
|
@include_once("modules/$modname/{$modname}.php");
|
|
if (class_exists($modname)) {
|
|
$instance = CRMEntity::getInstance($modname);
|
|
if ($instance) {
|
|
$tables[] = $instance->table_name;
|
|
$tables[] = $instance->customFieldTable[0];
|
|
}
|
|
}
|
|
$tables = array_filter($tables);
|
|
if (count($tables) > 0) {
|
|
foreach ($tables as $modTable) {
|
|
if (Vtecrm_Utils::CheckTable($modTable)) {
|
|
$dropq = $adb->datadict->DropTableSQL($modTable);
|
|
$adb->datadict->ExecuteSQLArray($dropq);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Delete all the files for the specified custom module.
|
|
*/
|
|
public function deleteModuleFiles($modname) {
|
|
global $adb, $table_prefix;
|
|
|
|
$this->log('Removing module files...');
|
|
|
|
$this->rrmdir("modules/$modname");
|
|
$this->rrmdir("cron/modules/$modname");
|
|
$this->rrmdir("Smarty/templates/modules/$modname");
|
|
|
|
return true;
|
|
}
|
|
|
|
protected function rrmdir($dir) {
|
|
if (is_dir($dir)) {
|
|
$objects = scandir($dir);
|
|
foreach ($objects as $object) {
|
|
if ($object != "." && $object != "..") {
|
|
$subpath = $dir.DIRECTORY_SEPARATOR.$object;
|
|
if (filetype($subpath) == "dir") $this->rrmdir($subpath); else unlink($subpath);
|
|
}
|
|
}
|
|
reset($objects);
|
|
rmdir($dir);
|
|
} elseif (is_file($dir)) {
|
|
unlink($dir);
|
|
}
|
|
}
|
|
|
|
protected function deleteRowsWithColumnValue($column, $value, $fuzzy = false) {
|
|
global $adb, $table_prefix;
|
|
|
|
$list = $this->getTablesWithColumn($column, $fuzzy);
|
|
if ($list && is_array($list)) {
|
|
foreach ($list as $table) {
|
|
if ($fuzzy) {
|
|
list($tablename, $columnname) = explode('.', $table, 2);
|
|
} else {
|
|
$tablename = $table;
|
|
$columnname = $column;
|
|
}
|
|
$adb->format_columns($columnname);
|
|
$q = "DELETE FROM $tablename WHERE $columnname = ?";
|
|
$adb->pquery($q, array($value));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// use only alphanumeric names for the column
|
|
protected function getTablesWithColumn($column, $fuzzy = false) {
|
|
global $adb, $dbconfig;
|
|
|
|
$dbname = $dbconfig['db_name'];
|
|
$params = array();
|
|
|
|
// crmv@167431
|
|
// crmv@73504
|
|
if ($adb->isMysql()) {
|
|
// use a faster method
|
|
$list = array();
|
|
$tables = $this->getMysqlTables();
|
|
foreach ($tables as $tablename=>$tablefields) {
|
|
if ($fuzzy) {
|
|
foreach ($tablefields as $colfield) {
|
|
if (stripos($colfield,$column) !== false) $list[] = $tablename.'.'.$colfield;
|
|
}
|
|
} else {
|
|
if (in_array($column,$tablefields)) $list[] = $tablename;
|
|
}
|
|
}
|
|
return $list;
|
|
} elseif ($adb->isPostgres()) {
|
|
// crmv@167431e
|
|
// crmv@140072
|
|
if ($fuzzy) {
|
|
$query = "SELECT table_name, column_name FROM information_schema.columns INNER JOIN information_schema.tables USING (table_schema,table_name) WHERE table_schema = '$dbname' AND column_name LIKE '%$column%' AND table_type = 'BASE TABLE'";
|
|
} else {
|
|
$query = "SELECT table_name FROM information_schema.columns INNER JOIN information_schema.tables USING (table_schema,table_name) WHERE table_schema = '$dbname' AND column_name = ? AND table_type = 'BASE TABLE'";
|
|
$params = array($column);
|
|
}
|
|
// crmv@140072e
|
|
} elseif ($adb->isMssql()) {
|
|
if ($fuzzy) {
|
|
$query = "SELECT table_name, column_name FROM information_schema.columns WHERE table_catalog = '$dbname' AND table_schema = 'dbo' AND column_name LIKE '%$column%'";
|
|
} else {
|
|
$query = "SELECT table_name FROM information_schema.columns WHERE table_catalog = '$dbname' AND table_schema = 'dbo' AND column_name = ?";
|
|
$params = array($column);
|
|
}
|
|
// crmv@73504e
|
|
} elseif ($adb->isOracle()) {
|
|
if ($fuzzy) {
|
|
$query =
|
|
"SELECT object_name AS table_name, user_tab_cols.column_name
|
|
FROM user_objects
|
|
INNER JOIN user_tab_cols ON user_objects.object_name = user_tab_cols.table_name
|
|
WHERE user_objects.object_type = 'TABLE' AND user_tab_cols.column_name LIKE '%$column%'";
|
|
} else {
|
|
$query =
|
|
"SELECT object_name AS table_name
|
|
FROM user_objects
|
|
INNER JOIN user_tab_cols ON user_objects.object_name = user_tab_cols.table_name
|
|
WHERE user_objects.object_type = 'TABLE' AND user_tab_cols.column_name = ?";
|
|
$params = array(strtoupper($column));
|
|
}
|
|
} else {
|
|
// database type not supported
|
|
return false;
|
|
}
|
|
|
|
$list = array();
|
|
$res = $adb->pquery($query, $params);
|
|
if ($res && $adb->num_rows($res) > 0) {
|
|
while ($row = $adb->FetchByAssoc($res,-1, false)) {
|
|
if ($fuzzy) {
|
|
$col = $row['table_name'].'.'.$row['column_name'];
|
|
} else {
|
|
$col = $row['table_name'];
|
|
}
|
|
$list[] = $col;
|
|
}
|
|
}
|
|
return $list;
|
|
}
|
|
|
|
// crmv@167431
|
|
protected function getMysqlTables(){
|
|
global $adb;
|
|
|
|
if (empty(self::$dbtables)){
|
|
$res = $adb->query("SHOW TABLES");
|
|
if ($res && $adb->num_rows($res) > 0) {
|
|
while ($row = $adb->fetch_array_no_html($res)) {
|
|
$table = $row[0];
|
|
//get column definition
|
|
$tablefields = array();
|
|
$res1 = $adb->query("DESCRIBE `{$table}`"); // crmv@205759
|
|
if ($res1 && $adb->num_rows($res1) > 0) {
|
|
while ($row1 = $adb->fetch_array_no_html($res1)) {
|
|
$tablefields[]=$row1[0];
|
|
}
|
|
self::$dbtables[$table] = $tablefields;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return self::$dbtables;
|
|
}
|
|
// crmv@167431e
|
|
|
|
|
|
}
|