/** * Runs a lighter but convenient update operation that's faster than the using row objects * * @TODO this should be a patch on nooku fw for when you're saving rowsets * * @author Stian Didriksen <*****@*****.**> * @param KDatabaseRowsetInterface | array * @param KDatabaseTableInterface * @return status */ public function update($rows, KDatabaseTableAbstract $table, $dbprefix = false) { if (!$dbprefix) { $dbprefix = KFactory::get('lib.joomla.config')->getValue('dbprefix'); } $mysqli = KFactory::get('lib.koowa.database.adapter.mysqli')->getConnection(); $statement = false; $base = $table->getDatabase()->quoteName($dbprefix . $table->getBase()); $columns = $table->getColumns(true); $primaries = $table->getPrimaryKey(); foreach ($rows as $id => $row) { //@TODO Do not import rows that are without ids, they can cause duplicate key errors //if(!isset($row['id'])) continue; //Reverse map first $row = $table->mapColumns($row, true); //Add missing columns for the sake of the prepared statement query foreach ($columns as $field => $column) { if (!isset($row[$field])) { $row[$field] = $column->default !== NULL ? $column->default : ''; } } //Filter out any extra columns. $data = array_intersect_key($row, $columns); //Get the primaries $where = array_intersect_key($row, $primaries); //Set the id back, to allow changing the primary key as used in the smf_users converter on the people table if (isset($where['id'])) { $where['id'] = (int) $id; } $where = $table->mapColumns($where); //Get the data and apply the column mappings $data = $table->mapColumns($data); //The key order is vital! ksort($data); ksort($where); //try { //Create the prepared statements that the other (likely 500 rows) will reuse if (!$statement) { foreach ($data as $key => $val) { $vals[] = $key . '=?'; } foreach ($where as $key => $val) { $keys[] = $key . ' = ?'; } $query = 'UPDATE ' . $base . ' SET ' . implode(', ', $vals) . ' WHERE ' . implode(' AND ', $keys); $statement = $mysqli->prepare($query) or die('failed to prepare query statement: ' . $query); //if($base == $table->getDatabase()->quoteName($dbprefix.'ninjaboard_people')) echo $query, "\n"; } $params = array(''); foreach ($data as $key => $val) { $params[0] .= false !== filter_var($val, FILTER_VALIDATE_INT) ? 'i' : 's'; $params[] = is_array($val) ? json_encode($val) : $val; } foreach ($where as $key => $val) { $params[0] .= false !== filter_var($val, FILTER_VALIDATE_INT) ? 'i' : 's'; $params[] = is_array($val) ? json_encode($val) : $val; } //if($base == $table->getDatabase()->quoteName($dbprefix.'ninjaboard_people')) echo implode($params, ', '), "\n"; //Bind the params to the prepared statement in a dynamic fashion call_user_func_array(array($statement, 'bind_param'), $this->refValues($params)); //Execute the prepared statement, it's super fast! //@TODO throw exception here if (!$statement->execute()) { echo $statement->error, "\n", 'with the bindings: ' . implode(', ', $params), "\n", 'and the following query:', $query, "\n"; } /* } catch(KDatabaseException $e) { // The following is for a query used should we get a duplicate key error $query = $table->getDatabase()->getQuery(); foreach($table->getPrimaryKey() as $key => $column) { $query->where($column->name, '=', $table->filter(array($key => $row[$key]), true)); } $table->getDatabase()->update($table->getBase(), KConfig::toData($data), $query); } //*/ } //printf("%d Row inserted.\n", $statement->affected_rows); /* */ if ($statement) { $statement->close(); } }