/**
  * Checks the plugin's database tables and upgrades if needed
  * Backend-use only.
  *
  * Sets for $this->getErrors() $this->checkdbErrors and for $this->getLogs() $this->checkdbLogs
  *
  * @param  int                    $pluginId
  * @param  boolean                $upgrade          FALSE: only check table, TRUE: upgrades table (depending on $dryRun)
  * @param  boolean                $dryRun           TRUE: doesn't do the modifying queries, but lists them, FALSE: does the job
  * @param  boolean|null           $strictlyColumns  FALSE: allow for other columns, TRUE: doesn't allow for other columns
  * @param  boolean|string|null    $strictlyEngine   FALSE: engine unchanged, TRUE: force engine change to type, updatewithtable: updates to match table, NULL: checks for attribute 'strict' in table
  * @return boolean|string         True: success: see logs, False: error, see errors, string: error
  */
 function checkDatabase($pluginId, $upgrade = false, $dryRun = false, $strictlyColumns = null, $strictlyEngine = null)
 {
     $success = null;
     $cbInstallXML = $this->getXml($pluginId);
     if (is_object($cbInstallXML)) {
         $db = $cbInstallXML->getElementByPath('database');
         if ($db !== false) {
             // get the element name:
             $e = $cbInstallXML->getElementByPath('name');
             $this->elementName($e->data());
             $cleanedElementName = strtolower(str_replace(array(" ", "."), array("", "_"), $this->elementName()));
             $sqlUpgrader = new DatabaseUpgrade(null, false);
             $sqlUpgrader->setDryRun($dryRun);
             $success = $sqlUpgrader->checkXmlDatabaseDescription($db, $cleanedElementName, $upgrade, $strictlyColumns, $strictlyEngine);
             /*
             var_dump( $success );
             echo "<br>\nERRORS: " . $sqlUpgrader->getErrors( "<br /><br />\n\n", "<br />\n" );
             echo "<br>\nLOGS: " . $sqlUpgrader->getLogs( "<br /><br />\n\n", "<br />\n" );
             exit;
             */
             $this->checkDatabaseErrors = $sqlUpgrader->getErrors(false);
             $this->checkDatabaseLogs = $sqlUpgrader->getLogs(false);
         }
     } else {
         $success = $cbInstallXML;
     }
     return $success;
 }
Beispiel #2
0
 /**
  * Handles SQL XML for the type of the field (backend use only!)
  * 	<database version="1">
  *		<table name="#__comprofilerUser" class="\CB\Database\Table\UserTable">
  *			<columns>
  *				<column name="_rate" nametype="namesuffix" type="sql:decimal(16,8)" unsigned="true" null="true" default="NULL" auto_increment="100" />
  *
  * TODO: Should be private, but is public because FIeldTable uses it !
  *
  * @param  FieldTable      $field                Field to adapt
  * @param  boolean|string  $change               FALSE: only check, TRUE: change database to match description (deleting non-matching columns if $strictlyColumns == true), 'drop': uninstalls columns/tables
  * @param  boolean         $dryRun               FALSE (default): tables are changed, TRUE: Dryrunning
  * @param  boolean         $preferredColumnType  Enforce preferred column type
  * @return array of array of array
  */
 public function adaptSQL($field, $change = true, $dryRun = false, $preferredColumnType = false)
 {
     $sqlUpgrader = new DatabaseUpgrade();
     $sqlUpgrader->setDryRun($dryRun);
     $old = $sqlUpgrader->setEnforcePreferredColumnType($preferredColumnType);
     $result = $this->checkFixSQL($sqlUpgrader, $field, $change);
     $sqlUpgrader->setEnforcePreferredColumnType($old);
     return $result;
 }
 /**
  * fix mandatory CB tables for tabs and fields
  *
  * @param  boolean  $dryRun  TRUE: Just dry-runs to log actions that would be taken, FALSE: Run fixes for real
  * @return bool
  */
 protected function _fixCBmandatoryDb($dryRun)
 {
     $this->_sqlUpgrader = new DatabaseUpgrade($this->_db, $this->_silentWhenOK);
     $this->_sqlUpgrader->setDryRun($dryRun);
     $sql = 'SELECT * FROM ' . $this->_db->NameQuote('#__comprofiler_tabs') . "\n ORDER BY " . $this->_db->NameQuote('tabid');
     // `tabid`, `pluginclass`
     $this->_db->setQuery($sql);
     $tabs = $this->_db->loadObjectList('tabid');
     if ($this->_db->getErrorNum()) {
         $this->_sqlUpgrader->setError('Tabs selection query error: ' . $this->_db->getErrorMsg());
         return false;
     }
     $sql = 'SELECT ' . $this->_db->NameQuote('fieldid') . ', ' . $this->_db->NameQuote('tabid') . "\n FROM " . $this->_db->NameQuote('#__comprofiler_fields') . "\n ORDER BY " . $this->_db->NameQuote('tabid');
     // `tabid`, `pluginclass`
     $this->_db->setQuery($sql);
     $fields = $this->_db->loadObjectList('fieldid');
     if ($this->_db->getErrorNum()) {
         $this->_sqlUpgrader->setError(sprintf('Fields selection query error: ' . $this->_db->getErrorMsg()), $sql);
         return false;
     }
     // 1) count and index tabs by core pluginclass and tabid holding array of fieldsids, so we can delete empty duplicate core tabs:
     $coreTabs = array();
     foreach ($tabs as $t) {
         if (in_array($t->pluginclass, $this->_tabsShouldBe)) {
             $coreTabs[$t->pluginclass][$t->tabid] = array();
         }
     }
     // 2) group fieldids by tabid
     // 3) add fields to $coreTabs[pluginclass][tabid][fieldid]
     $tabsFields = array();
     foreach ($fields as $f) {
         if (isset($tabs[$f->tabid])) {
             $tabsFields[$f->tabid][$f->fieldid] = $f->fieldid;
             if ($tabs[$f->tabid]->pluginclass != '') {
                 $coreTabs[$tabs[$f->tabid]->pluginclass][$f->tabid][$f->fieldid] = $f->fieldid;
             }
         }
     }
     // 4) delete empty duplicate core tabs according to $coreTabs[pluginclass][tabid][fieldid]
     foreach ($coreTabs as $tabIds) {
         if (count($tabIds) > 1) {
             // there is more than one core tab for this core plugin class ! We need to decide which to keep:
             $tabidCandidatesToKeep = array();
             // 1st priority: keep tabs that are enabled AND have fields:
             foreach ($tabIds as $tId => $tFields) {
                 if ($tabs[$tId]->enabled == 1 && count($tFields) > 0) {
                     $tabidCandidatesToKeep[] = $tId;
                 }
             }
             // 2nd priority: keep tabs that have fields:
             if (count($tabidCandidatesToKeep) == 0) {
                 foreach ($tabIds as $tId => $tFields) {
                     if (count($tFields) > 0) {
                         $tabidCandidatesToKeep[] = $tId;
                     }
                 }
             }
             // 3rd priority: keep tabs that are enabled:
             if (count($tabidCandidatesToKeep) == 0) {
                 foreach ($tabIds as $tId => $tFields) {
                     if ($tabs[$tId]->enabled == 1) {
                         $tabidCandidatesToKeep[] = $tId;
                     }
                 }
             }
             // 4th priority: keep tab with the correct id:
             if (count($tabidCandidatesToKeep) == 0) {
                 foreach ($tabIds as $tId => $tFields) {
                     if (isset($this->_tabsShouldBe[$tId]) && $tabs[$tId]->pluginclass == $this->_tabsShouldBe[$tId]) {
                         $tabidCandidatesToKeep[] = $tId;
                     }
                 }
             }
             // 5th priority: well no more priorities to think of ! : just take first one !
             if (count($tabidCandidatesToKeep) == 0) {
                 foreach ($tabIds as $tId => $tFields) {
                     $tabidCandidatesToKeep[] = $tId;
                     break;
                 }
             }
             // ok, by now we got at least one tab to keep: let's see which, in case we got more than one:
             if (count($tabidCandidatesToKeep) == 1) {
                 $tabToKeep = (int) $tabidCandidatesToKeep[0];
             } else {
                 $tabToKeep = null;
                 // a) has the right core id:
                 foreach ($tabidCandidatesToKeep as $tId) {
                     if (isset($this->_tabsShouldBe[$tId]) && $tabs[$tId]->pluginclass == $this->_tabsShouldBe[$tId]) {
                         $tabToKeep = $tId;
                         break;
                     }
                 }
                 // b) first with fields:
                 if ($tabToKeep === null) {
                     foreach ($tabidCandidatesToKeep as $tId) {
                         if (count($coreTabs[$tabs[$tId]->pluginclass][$tId]) > 0) {
                             $tabToKeep = $tId;
                             break;
                         }
                     }
                 }
                 // c) first enabled one:
                 if ($tabToKeep === null) {
                     foreach ($tabidCandidatesToKeep as $tId) {
                         if ($tabs[$tId]->enabled == 1) {
                             $tabToKeep = $tId;
                             break;
                         }
                     }
                 }
                 // d) first one:
                 if ($tabToKeep === null) {
                     foreach ($tabidCandidatesToKeep as $tId) {
                         $tabToKeep = $tId;
                         break;
                     }
                 }
             }
             if ($tabToKeep !== null) {
                 $tabsToDelete = array_diff(array_keys($tabIds), array($tabToKeep));
                 // first reassign the fields of the tabs to delete:
                 $fieldsToReassign = array();
                 foreach ($tabIds as $tId => $tFields) {
                     if ($tId != $tabToKeep && count($tFields) > 0) {
                         $fieldsToReassign = array_merge($fieldsToReassign, $tFields);
                     }
                 }
                 if (count($fieldsToReassign) > 0) {
                     $sql = 'UPDATE ' . $this->_db->NameQuote('#__comprofiler_fields') . ' SET ' . $this->_db->NameQuote('tabid') . ' = ' . (int) $tabToKeep . "\n WHERE " . $this->_db->NameQuote('fieldid') . ' IN ' . $this->_db->safeArrayOfIntegers($fieldsToReassign);
                     if (!($dryRun || $this->_db->query($sql))) {
                         $this->_sqlUpgrader->setError('Failed changing fieldids ' . $this->_db->safeArrayOfIntegers($fieldsToReassign) . ' from duplicates of kept core tabid: ' . $tabToKeep . ' because of error:' . $this->_db->getErrorMsg(), $sql);
                         break;
                     } else {
                         $this->_sqlUpgrader->setLog('Changed fieldids ' . $this->_db->safeArrayOfIntegers($fieldsToReassign) . ' from duplicates of kept core tabid: ' . $tabToKeep, $sql, 'change');
                     }
                 }
                 // c) remove duplicate core tabs:
                 $sql = 'DELETE FROM ' . $this->_db->NameQuote('#__comprofiler_tabs') . "\n WHERE " . $this->_db->NameQuote('tabid') . ' IN ' . $this->_db->safeArrayOfIntegers($tabsToDelete);
                 if (!($dryRun || $this->_db->query($sql))) {
                     $this->_sqlUpgrader->setError('Failed deleting duplicates tabids ' . $this->_db->safeArrayOfIntegers($tabsToDelete) . ' of the used core tabid: ' . $tabToKeep . ' because of error:' . $this->_db->getErrorMsg(), $sql);
                     break;
                 } else {
                     $this->_sqlUpgrader->setLog('Deleted duplicate core tabs tabids ' . $this->_db->safeArrayOfIntegers($tabsToDelete) . ' of the used core tabid: ' . $tabToKeep, $sql, 'change');
                 }
             }
         }
     }
     // 5) refetch tabs with now free space at reserved positions:
     $sql = 'SELECT * FROM ' . $this->_db->NameQuote('#__comprofiler_tabs') . "\n ORDER BY " . $this->_db->NameQuote('tabid');
     // `tabid`, `pluginclass`
     $this->_db->setQuery($sql);
     $tabs = $this->_db->loadObjectList('tabid');
     if ($this->_db->getErrorNum()) {
         $this->_sqlUpgrader->setError('Tabs 2nd selection query error: ' . $this->_db->getErrorMsg(), $sql);
         return false;
     }
     unset($coreTabs);
     // this one is now invalid, and not needed anymore
     $sql = 'SELECT ' . $this->_db->NameQuote('fieldid') . ', ' . $this->_db->NameQuote('tabid') . "\n FROM " . $this->_db->NameQuote('#__comprofiler_fields') . "\n ORDER BY " . $this->_db->NameQuote('tabid');
     $this->_db->setQuery($sql);
     $fields = $this->_db->loadObjectList('fieldid');
     if ($this->_db->getErrorNum()) {
         $this->_sqlUpgrader->setError('Fields 3nd selection query error: ' . $this->_db->getErrorMsg(), $sql);
         return false;
     }
     // group fieldids by tabid
     $tabsFields = array();
     foreach ($fields as $f) {
         if (isset($tabs[$f->tabid])) {
             $tabsFields[$f->tabid][$f->fieldid] = $f->fieldid;
         }
     }
     // 6) check tabs one by one, making room in reserved positions:
     foreach ($tabs as $t) {
         if (isset($this->_tabsShouldBe[$t->tabid]) && $t->pluginclass == $this->_tabsShouldBe[$t->tabid]) {
             // ok, cool, tabid and plugin matches: no corrective action:
             continue;
         }
         if (isset($this->_tabsShouldBe[$t->tabid])) {
             // not ok: tabid is taken by another tab: we need to relocate this tab at last position:
             // a) insert same tab in another tabid
             $oldTabId = $t->tabid;
             if (!$dryRun) {
                 $t->tabid = null;
                 if (!$this->_db->insertObject('#__comprofiler_tabs', $t, 'tabid')) {
                     $this->_sqlUpgrader->setError('Failed moving (inserting) non-core tabid: ' . $oldTabId . ' because of error:' . $this->_db->getErrorMsg(), $sql);
                     break;
                 }
                 $t->tabid = $this->_db->insertid();
             } else {
                 $t->tabid = $t->tabid + 10000;
                 // just to fake the insert
             }
             $this->_sqlUpgrader->setLog('Inserted old tabid ' . $oldTabId . ' as new tabid ' . $t->tabid, $dryRun ? 'INSERT tabobject' : $this->_db->getQuery(), 'change');
             // b) change fields' tabid:
             if (isset($tabsFields[$oldTabId]) && count($tabsFields[$oldTabId]) > 0) {
                 $sql = 'UPDATE ' . $this->_db->NameQuote('#__comprofiler_fields') . ' SET ' . $this->_db->NameQuote('tabid') . ' = ' . (int) $t->tabid . "\n WHERE " . $this->_db->NameQuote('tabid') . ' = ' . (int) $oldTabId;
                 if (!($dryRun || $this->_db->query($sql))) {
                     $this->_sqlUpgrader->setError('Failed changing fields from old non-core tab with core tabid: ' . $oldTabId . ' to new tabid: ' . $t->tabid . ' because of error:' . $this->_db->getErrorMsg(), $sql);
                     break;
                 } else {
                     $this->_sqlUpgrader->setLog('Changed fields from old non-core tab with core tabid: ' . $oldTabId . ' (that must be for ' . $this->_tabsShouldBe[$oldTabId] . ') to new tabid: ' . $t->tabid, $sql, 'change');
                 }
             }
             // c) remove old tab:
             $sql = 'DELETE FROM ' . $this->_db->NameQuote('#__comprofiler_tabs') . "\n WHERE " . $this->_db->NameQuote('tabid') . ' = ' . (int) $oldTabId;
             if (!($dryRun || $this->_db->query($sql))) {
                 $this->_sqlUpgrader->setError('Failed deleting old non-core tabid: ' . $oldTabId . ' which is already copied to new tabid: ' . $t->tabid . ' because of error:' . $this->_db->getErrorMsg(), $sql);
                 break;
             } else {
                 $this->_sqlUpgrader->setLog('Deleted old non-core tabid: ' . $oldTabId . ' which is already copied to new tabid: ' . $t->tabid, $sql, 'change');
             }
         }
     }
     // 7) refetch tabs with now free space at reserved positions as well as fields and recompute $tabFields:
     $sql = 'SELECT * FROM ' . $this->_db->NameQuote('#__comprofiler_tabs') . "\n ORDER BY " . $this->_db->NameQuote('tabid');
     // `tabid`, `pluginclass`
     $this->_db->setQuery($sql);
     $tabs = $this->_db->loadObjectList('tabid');
     if ($this->_db->getErrorNum()) {
         $this->_sqlUpgrader->setError('Tabs 3rd selection query error: ' . $this->_db->getErrorMsg(), $sql);
         return false;
     }
     $sql = 'SELECT ' . $this->_db->NameQuote('fieldid') . ', ' . $this->_db->NameQuote('tabid') . "\n FROM " . $this->_db->NameQuote('#__comprofiler_fields') . "\n ORDER BY " . $this->_db->NameQuote('tabid');
     $this->_db->setQuery($sql);
     $fields = $this->_db->loadObjectList('fieldid');
     if ($this->_db->getErrorNum()) {
         $this->_sqlUpgrader->setError('Fields 3nd selection query error: ' . $this->_db->getErrorMsg(), $sql);
         return false;
     }
     // group fieldids by tabid
     $tabsFields = array();
     foreach ($fields as $f) {
         if (isset($tabs[$f->tabid])) {
             $tabsFields[$f->tabid][$f->fieldid] = $f->fieldid;
         }
     }
     // 8) check tabs one by one, moving tabs back to reserved positions if needed:
     foreach ($tabs as $t) {
         if (isset($this->_tabsShouldBe[$t->tabid]) && $t->pluginclass == $this->_tabsShouldBe[$t->tabid]) {
             // ok, cool, tabid and plugin matches: no corrective action:
             continue;
         }
         if (!isset($this->_tabsShouldBe[$t->tabid]) && in_array($t->pluginclass, $this->_tabsShouldBe)) {
             // ok we found a core CB tab which doesn't have the right id: the right id is now free, so just update the tab:
             $newTabId = array_search($t->pluginclass, $this->_tabsShouldBe);
             if ($newTabId !== false) {
                 // a) move the core tab to the right tabid:
                 $sql = 'UPDATE ' . $this->_db->NameQuote('#__comprofiler_tabs') . ' SET ' . $this->_db->NameQuote('tabid') . ' = ' . (int) $newTabId . "\n WHERE " . $this->_db->NameQuote('tabid') . ' = ' . (int) $t->tabid;
                 if (!($dryRun || $this->_db->query($sql))) {
                     $this->_sqlUpgrader->setError('Failed moving core tab from old tabid: ' . $t->tabid . ' to new tabid: ' . $newTabId . ' because of error:' . $this->_db->getErrorMsg(), $sql);
                     break;
                 } else {
                     $this->_sqlUpgrader->setLog('Moved core tab from old tabid: ' . $t->tabid . ' to new tabid: ' . $newTabId, $sql, 'change');
                 }
                 // b) change fields' tabid:
                 if (isset($tabsFields[$t->tabid]) && count($tabsFields[$t->tabid]) > 0) {
                     $sql = 'UPDATE ' . $this->_db->NameQuote('#__comprofiler_fields') . ' SET ' . $this->_db->NameQuote('tabid') . ' = ' . (int) $newTabId . "\n WHERE " . $this->_db->NameQuote('tabid') . ' = ' . (int) $t->tabid;
                     if (!($dryRun || $this->_db->query($sql))) {
                         $this->_sqlUpgrader->setError('Failed changing fields from old core tabid: ' . $t->tabid . ' to new tabid: ' . $newTabId . ' because of error:' . $this->_db->getErrorMsg(), $sql);
                         break;
                     } else {
                         $this->_sqlUpgrader->setLog('Changed fields from old core tabid: ' . $t->tabid . ' to new tabid: ' . $newTabId, $sql, 'change');
                     }
                 }
             }
         }
     }
     // now missing core tabs will be inserted in the new 1.2 upgrader in next step.
     return true;
 }