1. Сделаем свой CDbExtCommandBuilder, в случае update добавляем параметры, а с ignore вообще все просто, переопределяем весь метод, могут быть проблемы при обновлении фреймворка но не такие болезненные как при изменеии непосредственно кода фреймвокра.
Заметьте: $this->_connection пришлось заменить на $this->getDbConnection(), скорее всего где то не досмотрел, но времени в обрез было.
Код: Выделить всё
class CDbExtCommandBuilder extends CDbCommandBuilder
{
public function createInsertUpdateCommand($table,$data,$update)
{
$this->ensureTable($table);
$fields=array();
$values=array();
$updates=array();
$placeholders=array();
$i=0;
foreach($data as $name=>$value)
{
if(($column=$table->getColumn($name))!==null && ($value!==null || $column->allowNull))
{
$fields[]=$column->rawName;
if($value instanceof CDbExpression)
{
$placeholders[]=$value->expression;
foreach($value->params as $n=>$v)
$values[$n]=$v;
}
else
{
$placeholders[]=self::PARAM_PREFIX.$i;
$values[self::PARAM_PREFIX.$i]=$column->typecast($value);
$i++;
}
}
}
foreach($update as $name=>$value)
{
if(($column=$table->getColumn($name))!==null && ($value!==null || $column->allowNull))
{
if($value instanceof CDbExpression)
{
$updates[]=$column->rawName.'='.$value->expression;
}
else
{
$updates[]=$column->rawName.'='.self::PARAM_PREFIX.$i;
$values[self::PARAM_PREFIX.$i]=$column->typecast($value);
$i++;
}
}
}
if($fields===array())
{
$pks=is_array($table->primaryKey) ? $table->primaryKey : array($table->primaryKey);
foreach($pks as $pk)
{
$fields[]=$table->getColumn($pk)->rawName;
$placeholders[]='NULL';
}
}
$sql="INSERT INTO {$table->rawName} (".implode(', ',$fields).') VALUES ('.implode(', ',$placeholders).') ';
$sql.='ON DUPLICATE KEY UPDATE '.implode(', ', $updates);
$command=$this->getDbConnection()->createCommand($sql);
foreach($values as $name=>$value)
$command->bindValue($name,$value);
return $command;
}
public function createInsertIgnoreCommand($table,$data)
{
$this->ensureTable($table);
$fields=array();
$values=array();
$placeholders=array();
$i=0;
foreach($data as $name=>$value)
{
if(($column=$table->getColumn($name))!==null && ($value!==null || $column->allowNull))
{
$fields[]=$column->rawName;
if($value instanceof CDbExpression)
{
$placeholders[]=$value->expression;
foreach($value->params as $n=>$v)
$values[$n]=$v;
}
else
{
$placeholders[]=self::PARAM_PREFIX.$i;
$values[self::PARAM_PREFIX.$i]=$column->typecast($value);
$i++;
}
}
}
if($fields===array())
{
$pks=is_array($table->primaryKey) ? $table->primaryKey : array($table->primaryKey);
foreach($pks as $pk)
{
$fields[]=$table->getColumn($pk)->rawName;
$placeholders[]='NULL';
}
}
$sql="INSERT IGNORE INTO {$table->rawName} (".implode(', ',$fields).') VALUES ('.implode(', ',$placeholders).')';
$command=$this->getDbConnection()->createCommand($sql);
foreach($values as $name=>$value)
$command->bindValue($name,$value);
return $command;
}
}
2. Унаследуем наш класс CExtActiveRecord от ActiveRecord
Код: Выделить всё
class CExtActiveRecord extends CActiveRecord
{
/**
* Returns the command builder used by this AR.
* @return CDbCommandBuilder the command builder used by this AR
*/
public function getCommandBuilder()
{
return new CDbExtCommandBuilder(Yii::app()->db->getSchema());
}
private function insertExt($builder, $table, $command)
{
if(!$this->getIsNewRecord())
throw new CDbException(Yii::t('yii','The active record cannot be inserted to database because it is not new.'));
if($this->beforeSave())
{
Yii::trace(get_class($this).'.insert()','system.db.ar.CActiveRecord');
if($command->execute())
{
$primaryKey=$table->primaryKey;
if($table->sequenceName!==null)
{
if(is_string($primaryKey) && $this->$primaryKey===null)
$this->$primaryKey=$builder->getLastInsertID($table);
else if(is_array($primaryKey))
{
foreach($primaryKey as $pk)
{
if($this->$pk===null)
{
$this->$pk=$builder->getLastInsertID($table);
break;
}
}
}
}
$this->_pk=$this->getPrimaryKey();
$this->afterSave();
$this->setIsNewRecord(false);
$this->setScenario('update');
return true;
}
}
return false;
}
public function insertUpdate($update, $runValidation=true, $attributes=null)
{
if(!$runValidation || $this->validate($attributes))
if ($this->getIsNewRecord())
{
$builder=$this->getCommandBuilder();
$table=$this->getMetaData()->tableSchema;
$command=$builder->createInsertUpdateCommand($table,$this->getAttributes($attributes), $update);
return $this->insertExt($builder, $table, $command);
}
else
return $this->update($attributes);
}
public function insertIgnore($runValidation=true, $attributes=null)
{
if(!$runValidation || $this->validate($attributes))
if ($this->getIsNewRecord())
{
$builder=$this->getCommandBuilder();
$table=$this->getMetaData()->tableSchema;
$command=$builder->createInsertIgnoreCommand($table,$this->getAttributes($attributes));
return $this->insertExt($builder, $table, $command);
}
else
return $this->update($attributes);
}
}
3. Ну и после генерации модели заменяем класс родителя CActiveRecod на CExtActiveRecord.
4. Использование:
Код: Выделить всё
$queue = new Queue();
$queue->uid = $uid;
$queue->adapter = get_class($this);
$queue->insertIgnore();
$a = new Address();
$a->address = $address;
$a->postcode = $post;
$a->city = $city;
$a->insertUpdate(array(
'update' => new CDbExpression('NOW()')
));
Т.к. это мой первый опыт с Yii, приветствуются замечания и дополнения.