public function save()
{
$iterator = $this->getIterator();
$pk = $iterator->getPrimaryKey();
if (empty($pk)) {
throw new ModelException(sprintf("Primary key has not been defined with @Id tag for %s", get_class($this)));
}
$stmtPk = '';
$stmtFields = '';
$stmtUpdate = '';
$argumentsPk = [];
$arguments1 = [];
$arguments2 = [];
foreach ($iterator->fields() as $field) {
if ($this->{$field->name} === null && isset($field->generatedValue)) {
if ($field->generatedValue->strategy == GeneratedValue::STRATEGY_CUSTOM) {
if (!$field->type instanceof GeneratedValueTypeInterface) {
throw new ModelException(sprintf("Unable to generate value for %s field. Type %s should implement " . "Scalr\\Model\\Type\\GeneratedValueTypeInterface", $field->name, get_class($field->type)));
}
$this->{$field->name} = $field->getType()->generateValue($this);
} else {
if ($field->generatedValue->strategy == GeneratedValue::STRATEGY_AUTO) {
//Generated automatically by mysql
if (isset($field->id)) {
$postInsertField = $field;
}
continue;
} else {
throw new ModelException(sprintf("Type %s has not been implemented for GeneratedValue behaviour.", get_class($field->type)));
}
}
}
if (isset($field->id)) {
//Field takes a part in primary key
$stmtFields .= ', ' . $field->getColumnName() . ' = ' . $field->type->wh();
$arguments1[] = $field->type->toDb($this->{$field->name});
$stmtPk .= ' AND ' . $field->getColumnName() . ' = ' . $field->type->wh();
$argumentsPk[] = $field->type->toDb($this->{$field->name});
} else {
//Field does not take a part in primary key
if (!isset($this->{$field->name}) && $field->column->nullable) {
$stmtFields .= ', ' . $field->getColumnName() . ' = NULL';
$stmtUpdate .= ', ' . $field->getColumnName() . ' = NULL';
} else {
$stmtFields .= ', ' . $field->getColumnName() . ' = ' . $field->type->wh();
$arguments1[] = $field->type->toDb($this->{$field->name});
$stmtUpdate .= ', ' . $field->getColumnName() . ' = ' . $field->type->wh();
$arguments2[] = $field->type->toDb($this->{$field->name});
}
}
}
$stmtFields = substr($stmtFields, 1);
if ($stmtPk != '') {
$stmtPk = substr($stmtPk, 4);
}
if ($stmtUpdate != '') {
$stmtUpdate = substr($stmtUpdate, 1);
}
if ($this->_hasUniqueIndex() && $stmtPk !== '') {
//If table has some unique index it should not perform ON DUPLICATE KEY UPDATE clause.
//We need to do INSERT if the record does not exist or UPDATE otherwise by primary key.
//If postInsertField is set it indicates that INSERT statement is expected then
if (!isset($postInsertField)) {
//Checks if the record with such primary key already exists in database
$exists = $this->db()->GetOne("SELECT 1 FROM {$this->table()} WHERE " . $stmtPk . " LIMIT 1", $argumentsPk);
} else {
//INSERT statement must be used as it's a new record
$exists = false;
}
//Saves record making insert or update
$this->db()->Execute(($exists ? "UPDATE" : "INSERT") . " " . $this->table() . " " . "SET " . $stmtFields . " " . ($exists ? "WHERE " . $stmtPk . " LIMIT 1" : ""), $exists ? array_merge($arguments1, $argumentsPk) : $arguments1);
} else {
$this->db()->Execute("\n INSERT " . $this->table() . "\n SET " . $stmtFields . "\n " . ($stmtUpdate != '' ? "ON DUPLICATE KEY UPDATE " . $stmtUpdate : '') . "\n ", array_merge($arguments1, $arguments2));
}
if (isset($postInsertField)) {
//Set a value of the auto incrementing field into entity
$this->{$postInsertField->name} = $postInsertField->type->toPhp($this->db()->Insert_ID());
}
}