/** * Deletes this record (no checks) * canDelete should be called first to check if there are no orphan dependencies left. * * @param int $oid Key id of row to delete (otherwise it's the one of $this) (only int supported here) * @return boolean TRUE if OK, FALSE if error */ public function delete($oid = null) { $where = $this->getSafeWhereStatements($oid); if (empty($where)) { return false; } $query = "DELETE FROM " . $this->_db->NameQuote($this->_tbl) . "\n WHERE " . implode(' AND ', $where); $this->_db->setQuery($query); if ($this->_db->query()) { return true; } else { $this->_error = $this->_db->getErrorMsg(); return false; } }
/** * Returns error message of query if any. * * @return string The error message for the most recent query */ public function getErrorMsg() { return $this->_db->getErrorMsg(); }
/** * Creates a new table * * @param SimpleXMLElement $table Table * @param string $colNamePrefix Prefix to add to all column names * @return boolean True: success, False: failure */ protected function createTable(SimpleXMLElement $table, $colNamePrefix) { if ($table->getName() == 'table') { $tableName = $this->prefixedName($table, $colNamePrefix); $columns = $table->getElementByPath('columns'); if ($tableName && $columns !== false) { $engine = $table->getElementByPath('engine'); $tableEngine = null; if ($engine !== false) { $engineType = $engine->attributes('type'); if ($engineType !== null) { $engineTable = $engine->attributes('sameastable'); if ($engineTable !== null) { $sameEngine = $this->checkTableEngine($engineTable); } else { $sameEngine = null; } if ($sameEngine) { $tableEngine = $sameEngine; } else { $tableEngine = $engineType; } } } $sqlColumns = array(); $tableOptions = array(); foreach ($columns->children() as $column) { if ($column->getName() == 'column') { $colNamePrefixed = $this->prefixedName($column, $colNamePrefix); $sqlColumns[] = "\n " . $this->_db->NameQuote($colNamePrefixed) . ' ' . $this->fullColumnType($column, $tableName, $tableEngine); if ((int) $column->attributes('auto_increment')) { $tableOptions[] = 'AUTO_INCREMENT=' . (int) $column->attributes('auto_increment'); } } } $indexes = $table->getElementByPath('indexes'); if ($indexes !== false) { foreach ($indexes->children() as $index) { if ($index->getName() == 'index') { $sqlIndexText = $this->fullIndexType($index, $colNamePrefix); if ($sqlIndexText) { $sqlColumns[] = "\n " . $sqlIndexText; } } } } if (!$tableEngine) { $cbEngine = $this->checkTableEngine('#__comprofiler'); if ($cbEngine) { $tableEngine = $cbEngine; } else { $tableEngine = 'InnoDB'; } } $tableOptions[] = 'ENGINE=' . $tableEngine; $collation = $table->attributes('collation'); if ($collation && $this->_db->versionCompare('4.1')) { $charSet = substr($collation, 0, strpos($collation, '_')); if ($charSet) { $tableOptions[] = 'CHARACTER SET = ' . preg_replace('/[^a-z0-9_]/', '', $charSet); $tableOptions[] = 'COLLATE = ' . preg_replace('/[^a-z0-9_]/', '', $collation); } } $sql = 'CREATE TABLE ' . $this->_db->NameQuote($tableName) . ' (' . implode(',', $sqlColumns) . "\n )" . implode(', ', $tableOptions); if (!$this->doQuery($sql)) { $this->setError(sprintf('%s::createTableof Table %s failed with SQL error: %s', get_class($this), $tableName, $this->_db->getErrorMsg()), $sql); return false; } else { $this->setLog(sprintf('Table %s successfully created', $tableName), $sql, 'change'); return true; } } } return false; }
/** * 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; }