/** * Returns the JSON-encoded string for the CB Configuration * * @param DatabaseDriverInterface $db Database Driver * @return null|string JSON-encoded string (or NULL if failed) */ public static function getConfig(DatabaseDriverInterface $db) { $db->setQuery("SELECT " . $db->NameQuote('params') . "\n FROM " . $db->NameQuote('#__comprofiler_plugin') . "\n WHERE " . $db->NameQuote('id') . " = 1"); $json = $db->loadResult(); if ($json) { return (array) json_decode($json); } return array(); }
/** * If a left join is needed by the <data> $data element: * Adds if not yet added a JOIN statement for the <data> element $data * and returns the table AS alias for accessing the corresponding table. * Otherwise returns NULL. * * @param SimpleXmlElement $data * @param array $subFormula For process_reverse_sql_field ONLY (if we decide to use): SQL conditions in array which are imploded by AND for the merge * @return string|null Name of table alias (a to z) if the <data> element required a left join. */ protected function _addGetJoinAs($data, $subFormula = null) { $tableAs = null; $cnt_name = $data->attributes('name'); $cnt_as = $data->attributes('as'); $cnt_table = $data->attributes('table'); $cnt_key = $data->attributes('key'); $cnt_val = $data->attributes('value'); $cnt_valtype = $data->attributes('valuetype'); $cnt_joinkeys = $data->getElementByPath('joinkeys'); if ($cnt_table && $this->_table && ($cnt_table != $this->_table || $cnt_key && $cnt_val || $cnt_joinkeys)) { // Compute JOIN keyword, e.g. LEFT JOIN: $joinKeyword = $this->computeJoinKeyword($cnt_joinkeys); if ($cnt_joinkeys) { if (!$cnt_key && !$cnt_val) { // compute the array-indexes for the leftJoindTableKeyValueArray: foreach ($cnt_joinkeys->children() as $column) { /** @var $column SimpleXmlElement */ $cnt_key[] = $column->attributes('name'); $cnt_val[] = $column->attributes('value'); $cnt_valtype[] = $column->attributes('valuetype'); $subFormula[] = $column->attributes('operator') . $column->attributes('type'); // Could be this but that doesn't work for group-search in CB User Management, to check later why: // $subFormula[] = $this->_db->NameQuote( $column->attributes( 'name' )) . ' ' . $column->attributes( 'operator' ) . ' ' . $this->_currentTableAs . '.' // . ( in_array( $column->attributes( 'valuetype' ), array( 'sql:field' ) ) ? $this->_db->NameQuote( $column->attributes( 'value' ) ) : $column->attributes( 'value' ) ); } $cnt_key = implode('&', $cnt_key); $cnt_val = implode('&', $cnt_val); $cnt_valtype = implode('&', $cnt_valtype); // Above change would make this look like WHERE statements: sql:field`user_id` = a.`id` // done below: $subFormulaArrayKey = implode( '&', $subFormula ); } else { trigger_error(sprintf('SQLXML::addGetJoinAs notice: data %s has joinkeys and key="%s" and/or value="%s" at same time. Ignoring key and value.', $cnt_name, $cnt_key, $cnt_val), E_USER_NOTICE); } } $subFormulaArrayKey = is_array($subFormula) ? implode('&', $subFormula) : $subFormula; // if different table or same table but a key and a value are specified as self-join, // field value is taken from related record in other or self-joined table: if (isset($this->leftJoindTableKeyValueArray[$cnt_table][$cnt_key][$cnt_val][$cnt_valtype . $subFormulaArrayKey])) { $tableAs = $this->leftJoindTableKeyValueArray[$cnt_table][$cnt_key][$cnt_val][$cnt_valtype . $subFormulaArrayKey]; } else { $this->incrementTableAs(); if ($cnt_joinkeys) { $subFormulaReal = $this->process_joinkeys($cnt_joinkeys); $this->leftJoinArray[$this->tableAs] = $joinKeyword . ' ' . $this->_db->NameQuote($cnt_table) . ' AS ' . $this->tableAs . ' ON ' . $subFormulaReal; } elseif (!$cnt_valtype || $cnt_valtype == 'sql:field' || $cnt_valtype == 'sql:parentfield') { $this->leftJoinArray[$this->tableAs] = $joinKeyword . ' ' . $this->_db->NameQuote($cnt_table) . ' AS ' . $this->tableAs . ' ON ' . $this->tableAs . '.' . ($subFormula === null ? '`' . $cnt_key . '` = ' . ($cnt_valtype == 'sql:parentfield' ? $this->_currentTableAsStack[0] : $this->_currentTableAs) . '.`' . $cnt_val . '`' : implode(' AND ', $subFormula)); //TBD this $subFormula is a temporary simplification/hack for process_reverse_sql_field ONLY: not even sure if it's needed !!! : check if really needed. } elseif ($cnt_key && $cnt_val && $cnt_valtype) { $value = $this->sqlCleanQuote($cnt_val, $cnt_valtype); $this->leftJoinArray[$this->tableAs] = $joinKeyword . ' ' . $this->_db->NameQuote($cnt_table) . ' AS ' . $this->tableAs . ' ON ' . $this->tableAs . '.`' . $cnt_key . '` = ' . $value; } $this->leftJoindTableKeyValueArray[$cnt_table][$cnt_key][$cnt_val][$cnt_valtype . $subFormulaArrayKey] = $this->tableAs; $tableAs = $this->tableAs; } $this->leftJoinedFieldsTable[$cnt_as ? $cnt_as : $cnt_name] = $tableAs; } return $tableAs; }
/** * Internal method: Loads if needed all View Access Levels, and caches them * * @return string[] All View Access Levels as array( value => 'translated-text' ) */ protected function loadAllViewAccessLevels() { if ($this->allViewAccessLevels === null) { $query = 'SELECT a.' . $this->_db->NameQuote('id') . ' AS value' . ', a.' . $this->_db->NameQuote('title') . ' AS text' . ', a.' . $this->_db->NameQuote('rules') . ' AS assetrules' . "\n FROM " . $this->_db->NameQuote('#__viewlevels') . " AS a" . "\n ORDER BY a." . $this->_db->NameQuote('ordering') . " ASC"; $accessLevels = $this->_db->setQuery($query)->loadObjectList('value'); foreach ($accessLevels as $level) { $value = (int) $level->value; $text = JText::_($level->text); $this->allViewAccessLevels[$value] = $text; $this->allViewAccessLevelRules[$value] = $level->assetrules; } } return $this->allViewAccessLevels; }
/** * @deprecated 2.0 No use anymore for such functionality * * @param int $gid * @return array */ public function get_group_parent_ids($gid = null) { static $gids = array(); $gid = (int) $gid; if (!isset($gids[$gid])) { static $grps = null; static $paths = null; if (!isset($grps)) { $query = 'SELECT *' . "\n FROM " . $this->_db->NameQuote('#__usergroups') . "\n ORDER BY " . $this->_db->NameQuote('lft'); $this->_db->setQuery($query); $grps = $this->_db->loadObjectList('id'); } if (!array_key_exists($gid, $grps)) { return array(); } if (!isset($paths[$gid])) { $paths[$gid] = array(); foreach ($grps as $grp) { if ($grp->lft >= $grps[$gid]->lft && $grp->rgt <= $grps[$gid]->rgt) { $paths[$gid][] = $grp->id; } } } $type = $this->get_parent_container($grps[$gid], $grps); if ($type === 1 && $gid !== 6) { /** @noinspection PhpDeprecationInspection */ $paths[$gid] = array_merge($paths[$gid], $this->get_group_parent_ids(6)); } elseif ($type === 2 && $gid !== 8) { /** @noinspection PhpDeprecationInspection */ $paths[$gid] = array_merge($paths[$gid], $this->get_group_parent_ids(8)); } $paths[$gid] = array_unique($paths[$gid]); sort($paths[$gid], SORT_NUMERIC); $groups = $paths[$gid]; for ($i = 0, $n = count($groups); $i < $n; $i++) { $groups[$i] = (int) $groups[$i]; } $gids[$gid] = $groups; } return $gids[$gid]; }
/** * Computes a safe WHERE statements as array to implode with ' AND ' or returns FALSE if none. * * @param int|string|array $keys Key-value to use for primary key condition, or array of key => value pairs to match * @param array $tableReferences Table references, e.g. array( $this->_tbl => 'm' ). (Must be SQL-safe) * @param string $defaultTableReference Default table reference, e.g. 'm' (Must be SQL-safe) * @return array|boolean Check for ! empty( $where ) before using the resulting array! * * @throws \UnexpectedValueException * @throws \InvalidArgumentException */ protected function getSafeWhereStatements($keys, $tableReferences = array(), $defaultTableReference = '') { // Determine the keys to use into $keys: $primaryKeysTypes = $this->getPrimaryKeysTypes(); $primaryKeys = array_keys($primaryKeysTypes); if (empty($keys)) { $keys = array(); // If empty, use the value of the current key foreach ($primaryKeys as $key) { if (empty($this->{$key})) { // If empty primary key there's is no need to load/delete anything: return false; } $keys[$key] = $this->{$key}; } } elseif (!is_array($keys)) { if (count($this->getPrimaryKeysTypes()) != 1) { throw new \InvalidArgumentException('Table has multiple primary keys specified (or none), and only one primary key value provided in load().'); } $keys = array($primaryKeys[0] => $keys); } // Determine the WHERE array: $properties = $this->getPublicProperties(); $where = array(); foreach ($keys as $whereField => $whereValue) { if (!in_array($whereField, $properties)) { throw new \UnexpectedValueException(sprintf('Missing where-field %s of load() in class %s.', $whereField, get_class($this))); } if (isset($primaryKeysTypes[$whereField]) && $primaryKeysTypes[$whereField] == 'int' || is_int($whereValue)) { $safeWhereValue = (int) $whereValue; } else { $safeWhereValue = $this->_db->Quote($whereValue); } $tableRefPrefix = isset($tableReferences[$whereField]) ? $tableReferences[$whereField] . '.' : ($defaultTableReference ? $defaultTableReference . '.' : ''); $where[] = $tableRefPrefix . $this->_db->NameQuote($whereField) . ' = ' . $safeWhereValue; } return $where; }
/** * Converts a XML description of a SQL index into a full SQL type * * <index name="PRIMARY" type="primary"> * <column name="id" /> * </index> * <index name="rate_chars"> * <column name="rate" /> * <column name="_mychars" nametype="namesuffix" size="8" ordering="DESC" /> * </index> * <index name="myrate" type="unique" using="btree"> * <column name="rate" /> * </index> * * Returns: $fulltype: 'decimal(16,8) unsigned NULL DEFAULT NULL' * * @param SimpleXMLElement $index * @param string $colNamePrefix Prefix to add to all column names * @return string|boolean Full SQL creation type or NULL in case of no index/error */ protected function fullIndexType(SimpleXMLElement $index, $colNamePrefix) { $sqlIndexText = null; if ($index->getName() == 'index') { // first collect all columns of this index: $indexColumns = array(); foreach ($index->children() as $column) { if ($column->getName() == 'column') { $colNamePrefixed = $this->prefixedName($column, $colNamePrefix); $indexColText = $this->_db->NameQuote($colNamePrefixed); if ($column->attributes('size')) { $indexColText .= ' (' . (int) $column->attributes('size') . ')'; } if ($column->attributes('ordering')) { $indexColText .= ' ' . $this->_db->getEscaped($column->attributes('ordering')); } $indexColumns[] = $indexColText; } } if (count($indexColumns) > 0) { // then build the index creation SQL: if ($index->attributes('type')) { // PRIMARY, UNIQUE, FULLTEXT, SPATIAL: $sqlIndexText .= $this->_db->getEscaped(strtoupper($index->attributes('type'))) . ' '; } $sqlIndexText .= 'KEY '; if ($index->attributes('type') !== 'primary') { $sqlIndexText .= $this->_db->NameQuote($this->prefixedName($index, $colNamePrefix)) . ' '; } if ($index->attributes('using')) { // BTREE, HASH, RTREE: $sqlIndexText .= 'USING ' . $this->_db->getEscaped($index->attributes('using')) . ' '; } $sqlIndexText .= '(' . implode(', ', $indexColumns) . ')'; } } return $sqlIndexText; }
/** * Performs a table action on a click in table * * @return void * @throws \Exception */ protected function _performTableActions() { global $_CB_framework; if (!isset($_REQUEST[$this->name])) { return; } $subtask = cbGetParam($_REQUEST[$this->name], 'subtask', ''); if (!$subtask) { return; } $task_parsed = explode('/', $subtask); $cid = cbGetParam($_REQUEST[$this->name], 'idcid', array()); if (!is_array($cid)) { $ocid = $cid; $cid = array(); $cid[] = $ocid; } switch ($task_parsed[0]) { case 'orderup': case 'orderdown': case 'saveorder': if ($this->listFieldsRows) { if (isset($task_parsed[1])) { $field = $task_parsed[1]; $fieldNode = $this->listFieldsRows->getChildByNameAttr('field', 'name', $field); if (!$fieldNode) { $fieldNode = $this->listFieldsRows->getChildByNameAttr('param', 'name', $field); } } else { $field = null; $fieldNode = false; } if (!$fieldNode || $fieldNode->attributes('type') !== 'ordering' || !Access::authorised($fieldNode)) { $_CB_framework->enqueueMessage(CBTxt::T('This field can not ordered'), 'error'); return; } $dataModelClass = $this->class; if ($task_parsed[0] != 'saveorder') { $dataModelValue = $cid[0]; } else { $dataModelValue = null; } $row = $this->createLoadClass($dataModelClass, $dataModelValue); if (!$row) { $_CB_framework->enqueueMessage(CBTxt::T('No row data found'), 'error'); return; } if ($task_parsed[0] == 'saveorder') { $order = cbGetParam($_REQUEST[$this->name], $field, array(0)); } $where = ''; $orderinggroups = $fieldNode->getElementByPath('orderinggroups'); /** @var $orderinggroups SimpleXMLElement|null */ if ($orderinggroups) { foreach ($orderinggroups->children() as $group) { /** @var $group SimpleXMLElement */ $orderingFieldName = $group->attributes('name'); if ($group->getName() == 'ordering' && $orderingFieldName && array_key_exists($orderingFieldName, get_object_vars($row))) { if ($task_parsed[0] != 'saveorder') { $where .= $this->_db->NameQuote($orderingFieldName) . ' = ' . XmlTypeCleanQuote::sqlCleanQuote($row->{$orderingFieldName}, $group->attributes('type'), $this->_pluginParams, $this->_db) . ' AND '; } else { $where .= $orderingFieldName . "='\$row->" . $orderingFieldName . "' AND "; } } } } if ($task_parsed[0] != 'saveorder') { $inc = $task_parsed[0] == 'orderup' ? -1 : 1; /** @var OrderedTable $row */ $row->move($inc, $where . $field . " > -10000 AND " . $field . " < 10000 ", $field); } else { $this->saveOrder($cid, $row, $order, "\$condition = \"" . $where . $field . " > -10000 AND " . $field . " < 10000 \";", $field); } $_CB_framework->enqueueMessage(CBTxt::T('ROW_COUNT_ORDER_SUCCESS', 'Row ordered successfully!|%%COUNT%% rows ordered successfully!', array('%%COUNT%%' => count($cid)))); } break; case 'publish': case 'unpublish': case 'enable': case 'disable': case 'setfield': case 'doaction': if ($this->listFieldsRows) { $field = null; switch ($task_parsed[0]) { case 'publish': case 'unpublish': $value = $task_parsed[0] == 'publish' ? 1 : 0; $field = 'published'; break; case 'enable': case 'disable': $value = $task_parsed[0] == 'enable' ? 1 : 0; $field = 'enabled'; break; case 'setfield': $value = $task_parsed[2]; break; case 'doaction': $value = null; break; default: throw new \Exception(__FUNCTION__ . ': Impossible value'); } if (isset($task_parsed[1])) { $field = $task_parsed[1]; } /** @var SimpleXMLElement $fieldNode */ $fieldNode = $this->listFieldsRows->xpath('(//field[@name="' . $field . '"][@onclick="toggle"])[last()]'); if (!$fieldNode) { $fieldNode = $this->listFieldsRows->xpath('(//param[@name="' . $field . '"][@onclick="toggle"])[last()]'); } if (!$fieldNode) { // We're not a field toggle so lets check if we're a menu item for permission/usage checks: $fieldNode = $this->toolbarmenu->xpath('(//menu[@name="' . $field . '"])[last()]'); } if (!$fieldNode || !Access::authorised($fieldNode[0])) { $_CB_framework->enqueueMessage(CBTxt::T('THIS_FIELD_CAN_NOT_TOGGLE_TASK', 'This field can not toggle: [task]', array('[task]' => $task_parsed[0])), 'error'); return; } $fieldNode = $fieldNode[0]; $taskName = CBTxt::T($fieldNode->attributes('label')); if ($task_parsed[0] == 'setfield') { // Check field value if allowed: $this->registryEditVew->resolveXmlParamType($fieldNode); if ($fieldNode->getChildByNameAttributes('option')) { $valueNode = $fieldNode->getAnyChildByNameAttr('option', 'index', $value); if (!$valueNode) { $valueNode = $fieldNode->getAnyChildByNameAttr('option', 'value', $value); } if ($valueNode) { $valueLabel = CBTxt::T($valueNode->data()); if ($valueLabel) { $taskName = $valueLabel; } } else { $_CB_framework->enqueueMessage(CBTxt::T('This field can not be set to that value'), 'error'); return; } } } if (!$taskName) { $taskName = $task_parsed[0]; } if (count($cid) < 1) { $_CB_framework->enqueueMessage(CBTxt::T('SELECT_A_ROW_TO_TASK', 'Select a row to [task]', array('[task]' => strtolower($taskName))), 'error'); return; } $dataModelClass = $this->class; foreach ($cid as $c) { $dataModelValue = $c; $row = $this->createLoadClass($dataModelClass, $dataModelValue); if (!$row) { $_CB_framework->enqueueMessage(CBTxt::T('No row data found'), 'error'); return; } if ($task_parsed[0] == 'doaction') { $this->registryEditVew->pushModelOfData($row); $toggle = $this->registryEditVew->_form_private($field, $value, $fieldNode, null); $this->registryEditVew->popModelOfData(); if (!$toggle) { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_TASK_ROW_ID_ID_BECAUSE_ERROR', 'Cannot [task] row id [id] because: [error]', array('[id]' => $dataModelValue, '[task]' => strtolower($taskName), '[error]' => $row->getError())), 'error'); return; } } elseif ($row->{$field} != $value) { if (is_callable(array($row, 'historySetMessage'))) { $row->historySetMessage(ucfirst($task_parsed[0]) . ' ' . $field . ' from administration backend'); } if ($fieldNode->attributes('class') && $fieldNode->attributes('method')) { $this->registryEditVew->pushModelOfData($row); $toggle = $this->registryEditVew->_form_private($field, $value, $fieldNode, null); $this->registryEditVew->popModelOfData(); if (!$toggle) { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_TASK_ROW_ID_ID_BECAUSE_ERROR', 'Cannot [task] row id [id] because: [error]', array('[id]' => $dataModelValue, '[task]' => strtolower($taskName), '[error]' => $row->getError())), 'error'); return; } } elseif ($row->hasFeature('checkout')) { /** @var CheckedOrderedTable $row */ if (!$row->isCheckedOut($_CB_framework->myId())) { $row->{$field} = $value; if ($row->check()) { if (!$row->store()) { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_TASK_ROW_ID_ID_BECAUSE_ERROR', 'Cannot [task] row id [id] because: [error]', array('[id]' => $dataModelValue, '[task]' => strtolower($taskName), '[error]' => $row->getError())), 'error'); return; } } else { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_TASK_ROW_ID_ID_BECAUSE_ERROR', 'Cannot [task] row id [id] because: [error]', array('[id]' => $dataModelValue, '[task]' => strtolower($taskName), '[error]' => $row->getError())), 'error'); return; } $row->checkin(); } } else { $row->{$field} = $value; if ($row->check()) { if (!$row->store()) { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_TASK_ROW_ID_ID_BECAUSE_ERROR', 'Cannot [task] row id [id] because: [error]', array('[id]' => $dataModelValue, '[task]' => strtolower($taskName), '[error]' => $row->getError())), 'error'); return; } } else { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_TASK_ROW_ID_ID_BECAUSE_ERROR', 'Cannot [task] row id [id] because: [error]', array('[id]' => $dataModelValue, '[task]' => strtolower($taskName), '[error]' => $row->getError())), 'error'); return; } } } } $_CB_framework->enqueueMessage(CBTxt::T('ROW_COUNT_TASK_SUCCESS', '{1} Row [task] successfully!|%%COUNT%% rows [task] successfully!', array('%%COUNT%%' => count($cid), '[task]' => strtolower($taskName)))); } break; case 'editrows': if ($this->listFieldsRows) { if (count($cid) != 1) { $_CB_framework->enqueueMessage(CBTxt::T('SELECT_A_ROW_TO_TASK', 'Select a row to [task]', array('[task]' => 'edit')), 'error'); return; } if (isset($task_parsed[1])) { $field = $task_parsed[1]; } else { $field = 'tid'; } if ($this->_options['view'] == 'editPlugin') { $task = $this->_options['view']; } else { $task = 'editrow'; } $baseUrl = 'index.php?option=' . $this->_options['option'] . '&view=' . $task; if (isset($this->_options['pluginid'])) { $baseUrl .= '&cid=' . $this->_options['pluginid']; } $url = $baseUrl . '&table=' . $this->_tableBrowserModel->attributes('name') . '&action=editrow&' . urlencode($field) . '=' . urlencode($cid[0]); cbRedirect($url); } break; case 'deleterows': if ($this->listFieldsRows) { if (count($cid) < 1) { $_CB_framework->enqueueMessage(CBTxt::T('SELECT_A_ROW_TO_TASK', 'Select a row to [task]', array('[task]' => 'delete')), 'error'); return; } $dataModelClass = $this->class; foreach ($cid as $id) { $dataModelValue = $id; $row = $this->createLoadClass($dataModelClass, $dataModelValue); if (!$row) { $_CB_framework->enqueueMessage(CBTxt::T('No row data found'), 'error'); return; } if ($row->canDelete($dataModelValue)) { if (!$row->delete($dataModelValue)) { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_DELETE_ROW_ID_BECAUSE_ERROR', 'Cannot delete row id [id] because: [error]', array('[id]' => $dataModelValue, '[error]' => $row->getError())), 'error'); return; } } else { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_DELETE_ROW_ID_BECAUSE_ERROR', 'Cannot delete row id [id] because: [error]', array('[id]' => $dataModelValue, '[error]' => $row->getError())), 'error'); return; } } $_CB_framework->enqueueMessage(CBTxt::T('ROW_COUNT_DELETED_SUCCESS', 'Row deleted successfully!|%%COUNT%% rows deleted successfully!', array('%%COUNT%%' => count($cid)))); } break; case 'batchrows': if ($this->listFieldsRows) { if (count($cid) < 1) { $_CB_framework->enqueueMessage(CBTxt::T('SELECT_A_ROW_TO_TASK', 'Select a row to [task]', array('[task]' => 'batch')), 'error'); return; } $postData = array(); foreach ($this->_batchPossibilitesArray as $key => $value) { // <batchprocess><batch> if (!$this->isValueEmpty($value['internalvalue'])) { $field = $value['valuefield']; $postData[$field] = $value['internalvalue']; } // Reset back to null as we don't want the values reselected on display: $this->_batchPossibilitesArray[$key]['value'] = null; $this->_batchPossibilitesArray[$key]['internalvalue'] = $value['value']; } if (count($postData) < 1) { $_CB_framework->enqueueMessage(CBTxt::T('Nothing to process'), 'error'); return; } $dataModelClass = $this->class; foreach ($cid as $id) { $dataModelValue = $id; /** @var $row TableInterface */ $row = $this->createLoadClass($dataModelClass, $dataModelValue); if (!$row) { $_CB_framework->enqueueMessage(CBTxt::T('No row data found'), 'error'); return; } $rowPost = array(); foreach ($postData as $key => $value) { if (property_exists($row, $key)) { $rowPost[$key] = is_array($value) ? json_encode($value) : $value; } } if (count($rowPost) < 1) { $_CB_framework->enqueueMessage(CBTxt::T('Nothing to process'), 'error'); return; } if (!$row->bind($rowPost)) { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_BATCH_PROCESS_ROW_ID_ID_BECAUSE_ERROR', 'Cannot batch process row id [id] because: [error]', array('[id]' => $dataModelValue, '[error]' => $row->getError())), 'error'); return; } if (!$row->check()) { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_BATCH_PROCESS_ROW_ID_ID_BECAUSE_ERROR', 'Cannot batch process row id [id] because: [error]', array('[id]' => $dataModelValue, '[error]' => $row->getError())), 'error'); return; } if (!$row->store()) { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_BATCH_PROCESS_ROW_ID_ID_BECAUSE_ERROR', 'Cannot batch process row id [id] because: [error]', array('[id]' => $dataModelValue, '[error]' => $row->getError())), 'error'); return; } } $_CB_framework->enqueueMessage(CBTxt::T('ROW_COUNT_SAVED_SUCCESS', 'Row saved successfully!|%%COUNT%% rows saved successfully!', array('%%COUNT%%' => count($cid)))); } break; case 'copyrows': if ($this->listFieldsRows) { if (count($cid) < 1) { $_CB_framework->enqueueMessage(CBTxt::T('SELECT_A_ROW_TO_TASK', 'Select a row to [task]', array('[task]' => 'copy')), 'error'); return; } $dataModelClass = $this->class; foreach ($cid as $id) { $dataModelValue = $id; /** @var $row TableInterface */ $row = $this->createLoadClass($dataModelClass, $dataModelValue); if (!$row) { $_CB_framework->enqueueMessage(CBTxt::T('No row data found'), 'error'); return; } if ($row->canCopy()) { if (!$row->copy()) { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_COPY_ROW_ID_ID_BECAUSE_ERROR', 'Cannot copy row id [id] because: [error]', array('[id]' => $dataModelValue, '[error]' => $row->getError())), 'error'); return; } } else { $_CB_framework->enqueueMessage(CBTxt::T('CANNOT_COPY_ROW_ID_ID_BECAUSE_ERROR', 'Cannot copy row id [id] because: [error]', array('[id]' => $dataModelValue, '[error]' => $row->getError())), 'error'); return; } } $_CB_framework->enqueueMessage(CBTxt::T('ROW_COUNT_COPIED_SUCCESS', 'Row copied successfully!|%%COUNT%% rows copied successfully!', array('%%COUNT%%' => count($cid)))); } break; case 'action': if ($this->listFieldsRows) { if (count($cid) != 1) { $_CB_framework->enqueueMessage(CBTxt::T('SELECT_A_ROW_TO_TASK', 'Select a row to [task]', array('[task]' => isset($task_parsed[1]) ? $task_parsed[1] : 'action')), 'error'); return; } if (isset($task_parsed[1])) { if (isset($task_parsed[2])) { $field = $task_parsed[2]; } else { $field = 'tid'; } $baseUrl = 'index.php?option=' . $this->_options['option'] . '&view=' . $this->_options['view']; if (isset($this->_options['pluginid'])) { $baseUrl .= '&cid=' . $this->_options['pluginid']; } $url = $baseUrl . '&table=' . $this->_tableBrowserModel->attributes('name') . '&action=' . urlencode($task_parsed[1]) . '&' . urlencode($field) . '=' . urlencode($cid[0]); cbRedirect($url); } } break; default: break; } //TBD cbRedirect( $_CB_framework->backendUrl( 'index.php?option=com_comprofiler&task=showPlugins', $msg ) ); }
/** * 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; }