Beispiel #1
0
 /**
  * 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();
 }
Beispiel #2
0
 /**
  * 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;
 }
Beispiel #4
0
 /**
  * @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];
 }
Beispiel #5
0
 /**
  * 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;
 }
Beispiel #6
0
 /**
  * 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;
 }
Beispiel #7
0
 /**
  * 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;
 }