Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii2: get raw sql of model->save()

I want to add record to a table with ActiveRecord.

Here is my code:

$model = new Article();
$model->title = 'test title';
$model->content = 'test content';
$model->category_id = 1;
$model->author_id = 1;
if ($model->validate()) {
    $model->save();
}

$model->validate() returns true, but $model->save() returns false.

How to find generated raw sql of $model->save()?

Meanwhile:

$model->save()->rawSql is null and $model->getErrors() returns empty array.

In debug, all queries are logged, but I did not find any insert or update query.

like image 942
ingenious Avatar asked May 10 '15 09:05

ingenious


People also ask

How to write SQL query in Yii2?

Call yii\db\QueryBuilder to generate a SQL statement based on the current construct of yii\db\Query; Create a yii\db\Command object with the generated SQL statement; Call a query method (e.g. queryAll()) of yii\db\Command to execute the SQL statement and retrieve the data.

How to write query in yii?

use createcommand() method: use yii\db\Query(); $connection = \Yii::$app->db; $query = new Query; $insql = $connection->createCommand("SELECT* FROM inventory ); $result=$insql->queryAll(); the above method list all data from the inventory table.

Is null in Yii2 query?

Yii2 will use "IS NULL" if the $values === null , but in case the value is supplied as an array, and one of those array elements is null, it will not get any special treatment, resulting in the query never matching any records with NULL value.

How to delete Record in Yii2?

To delete a single row of data, first retrieve the Active Record instance corresponding to that row and then call the yii\db\ActiveRecord::delete() method. $customer = Customer::findOne(123); $customer->delete(); You can call yii\db\ActiveRecord::deleteAll() to delete multiple or all rows of data.


2 Answers

$model->save()->rawSql call can not return null, it must throw an exception that you are trying to access property of non-object. $model->save() returns boolean value - either query executed successfully or not.

If $model->getErrors() returns empty array and query was not executed at all I'm pretty sure that something is wrong with model event handlers, especially beforeSave(), check it, it should not return false. Also check attached behaviors event handlers.

As for getting query. It's useless if it simply was not executed, but if it was, here are some ways to achieve it:

1) Probably the best way. Use debug panel. I also mentioned it here.

2) Look at logs as @robsch adviced.

You can't directly get raw SQL in code with $model->save(), It will call either insert() or update(). If you are interested, here is the part of code for insertInternal():

$values = $this->getDirtyAttributes($attributes);
if (empty($values)) {
    foreach ($this->getPrimaryKey(true) as $key => $value) {
        $values[$key] = $value;
    }
}
$db = static::getDb();
$command = $db->createCommand()->insert($this->tableName(), $values);
if (!$command->execute()) {
    return false;
}

If you call $command->rawSql you will get raw sql but you can't do that outside because the command is formed internally.

P.S. This piece of code:

if ($model->validate()) {
    $model->save();
}

doesn't make sense because $model->save() will call $model->validate() internally.

like image 137
arogachev Avatar answered Oct 13 '22 20:10

arogachev


This code won't show you exactly the raw sql but you'll get the query pre binding and the params

try {
    // this will simulate $model->save();
    $builder = $model->getCommandBuilder();
    $table = $model->getTableSchema();
    $command = $builder->createInsertCommand($table, $model->getAttributes());
    $command->_connection->enableParamLogging = true;
    $command->execute();
} catch (Exception $e) {
    // getText() will print the query with the binding params
    // getAttributes() will give you the attributes injected
    var_dump($command->getText());               
    var_dump($model->getAttributes());
    die();
}

The result will look like:

"INSERT INTO `fruit` (`order`, `name`, `season`) VALUES (:yp0, :yp1,:yp2)"

array(2) {
  ["order"] =>  int(1),
  ["name"] =>  null,
  ["season"] =>  null
}
like image 1
borracciaBlu Avatar answered Oct 13 '22 20:10

borracciaBlu