public function update(array $args, $options = array())
{
$schema = $this->getSchema();
// check if the record is loaded.
$k = static::PRIMARY_KEY;
if ($k && !isset($args[$k]) && !isset($this->_data[$k])) {
return $this->reportError('Record is not loaded, Can not update record.', array('args' => $args));
}
if (!$this->currentUserCan($this->getCurrentUser(), 'update', $args)) {
return $this->reportError('Permission denied. Can not update record.', array('args' => $args));
}
// check if we get primary key value
// here we allow users to specifty primary key value from arguments if the record is not loaded.
$kVal = null;
if (isset($args[$k]) && is_scalar($args[$k])) {
$kVal = intval($args[$k]);
} elseif (isset($this->_data[$k])) {
$kVal = intval($this->_data[$k]);
}
if (!$kVal) {
throw new Exception('Primary key value is undefined.');
}
$origArgs = $args;
$dsId = $this->writeSourceId;
$conn = $this->getWriteConnection();
$driver = $this->getWriteQueryDriver();
$sql = null;
$vars = null;
$arguments = new ArgumentArray();
$query = new UpdateQuery();
$validationError = false;
$validationResults = array();
$updateArgs = array();
$schema = $this->getSchema();
$args = $this->beforeUpdate($args);
if ($args === false) {
return $this->reportError(_('Update failed'), array('args' => $args));
}
// foreach mixin schema, run their beforeUpdate method,
$args = array_intersect_key($args, array_flip($schema->columnNames));
foreach ($schema->columns as $n => $c) {
if (isset($args[$n]) && !$args[$n] && !$c->primary) {
if ($val = $c->getDefaultValue($this, $args)) {
$args[$n] = $val;
}
}
// column validate (value is set.)
if (!array_key_exists($n, $args)) {
continue;
}
// if column is required (can not be empty) // and default is defined.
if ($c->required && array_key_exists($n, $args) && $args[$n] === null) {
return $this->reportError("Value of {$n} is required.");
}
// TODO: Do not render immutable field in ActionKit
// XXX: calling ::save() might update the immutable columns
if ($c->immutable) {
continue;
// TODO: render as a validation results?
// continue;
// return $this->reportError( "You can not update $n column, which is immutable.", array('args' => $args));
}
if ($args[$n] !== null && !is_array($args[$n]) && !$args[$n] instanceof Raw) {
$args[$n] = $c->typeCasting($args[$n]);
}
// The is_array function here is for checking raw sql value.
if ($args[$n] !== null && !is_array($args[$n]) && !$args[$n] instanceof Raw) {
if (false === $c->checkTypeConstraint($args[$n])) {
return $this->reportError($args[$n] . ' is not ' . $c->isa . ' type');
}
}
if ($c->filter || $c->canonicalizer) {
$args[$n] = $c->canonicalizeValue($args[$n], $this, $args);
}
if ($validationResult = $this->_validateColumn($c, $args[$n], $args)) {
$validationResults[$n] = $validationResult;
if (!$validationResult['valid']) {
$validationError = true;
}
}
// deflate the values into query
/*
if ($args[$n] instanceof Raw) {
$updateArgs[$n] = $args[$n];
} else {
$updateArgs[$n] = $c->deflate($args[$n], $driver);
}
*/
// use parameter binding for binding
$val = $args[$n];
if (is_scalar($args[$n]) || is_null($args[$n])) {
$updateArgs[$n] = $bind = new Bind($n, $driver->cast($args[$n]));
$arguments->bind($bind);
} elseif ($args[$n] instanceof Raw) {
$updateArgs[$n] = $args[$n];
} else {
$updateArgs[$n] = $bind = new Bind($n, $c->deflate($args[$n], $driver));
$arguments->bind($bind);
}
}
if ($validationError) {
return $this->reportError('Validation failed.', array('validations' => $validationResults));
}
if (empty($updateArgs)) {
return $this->reportError('Empty args');
}
// TODO: optimized to built cache
$query->set($updateArgs);
$query->update($this->table);
$query->where()->equal($k, $kVal);
$sql = $query->toSql($driver, $arguments);
$stm = $conn->prepare($sql);
$stm->execute($arguments->toArray());
// Merge updated data.
//
// if $args contains a raw SQL string,
// we should reload data from database
if (isset($options['reload'])) {
$this->reload();
} else {
$this->_data = array_merge($this->_data, $args);
}
$this->afterUpdate($origArgs);
/*
}
catch(PDOException $e)
{
throw new QueryException("Record update failed", $this, $e, array(
'driver' => get_class($driver),
'args' => $args,
'sql' => $sql,
'validations' => $validationResults,
));
}
*/
return $this->reportSuccess('Updated successfully', array('id' => $kVal, 'sql' => $sql, 'args' => $args, 'type' => Result::TYPE_UPDATE));
}