diff --git a/docs/guide/db-active-record.md b/docs/guide/db-active-record.md index e93a0f4b95..dd70f4c024 100644 --- a/docs/guide/db-active-record.md +++ b/docs/guide/db-active-record.md @@ -633,7 +633,7 @@ try { $customer->save(); // ...other DB operations... $transaction->commit(); -} catch(\Exception $e) { +} catch(\Exception $e) { // replace \Exception with \Throwable when you are using PHP 7 $transaction->rollBack(); throw $e; } diff --git a/docs/guide/db-dao.md b/docs/guide/db-dao.md index b344b11824..f8a207425b 100644 --- a/docs/guide/db-dao.md +++ b/docs/guide/db-dao.md @@ -336,7 +336,7 @@ try { $transaction->commit(); -} catch(\Exception $e) { +} catch(\Exception $e) { // replace \Exception with \Throwable when you are using PHP 7 $transaction->rollBack(); @@ -421,13 +421,13 @@ try { try { $db->createCommand($sql2)->execute(); $innerTransaction->commit(); - } catch (\Exception $e) { + } catch (\Exception $e) { // replace \Exception with \Throwable when you are using PHP 7 $innerTransaction->rollBack(); throw $e; } $outerTransaction->commit(); -} catch (\Exception $e) { +} catch (\Exception $e) { // replace \Exception with \Throwable when you are using PHP 7 $outerTransaction->rollBack(); throw $e; } @@ -570,7 +570,7 @@ try { $db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute(); $transaction->commit(); -} catch(\Exception $e) { +} catch(\Exception $e) { // replace \Exception with \Throwable when you are using PHP 7 $transaction->rollBack(); throw $e; } diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index afaa3fd00b..156edaf279 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -54,7 +54,7 @@ Yii Framework 2 Change Log - Enh #12145: Added `beforeCacheResponse` and `afterRestoreResponse` to `yii\filters\PageCache` to be more easily extendable (sergeymakinen) - Enh #12390: Avoid creating queries with false where condition (`0=1`) when fetching relational data (klimov-paul) - Enh #12399: Added `ActiveField::addAriaAttributes` property for `aria-required` and `aria-invalid` attributes rendering (Oxyaction, samdark) -- Enh #12619: Added catch `Throwable` in `yii\base\ErrorHandler::handleException()` (rob006) +- Enh #12619: Added catch `Throwable` in `yii\base\ErrorHandler::handleException()`, transactions and simlar places where consistency must be kept after exception (rob006, cebe) - Enh #12659: Suggest alternatives when console command was not found (mdmunir, cebe) - Enh #12726: `yii\base\Application::$version` converted to `yii\base\Module::$version` virtual property, allowing to specify version as a PHP callback (klimov-paul) - Enh #12732: Added `is_dir()` validation to `yii\helpers\BaseFileHelper::findFiles()` method (zalatov, silverfire) diff --git a/framework/db/ActiveRecord.php b/framework/db/ActiveRecord.php index d403914bc4..06c67c4b94 100644 --- a/framework/db/ActiveRecord.php +++ b/framework/db/ActiveRecord.php @@ -439,6 +439,9 @@ class ActiveRecord extends BaseActiveRecord } catch (\Exception $e) { $transaction->rollBack(); throw $e; + } catch (\Throwable $e) { + $transaction->rollBack(); + throw $e; } } @@ -545,6 +548,9 @@ class ActiveRecord extends BaseActiveRecord } catch (\Exception $e) { $transaction->rollBack(); throw $e; + } catch (\Throwable $e) { + $transaction->rollBack(); + throw $e; } } @@ -585,6 +591,9 @@ class ActiveRecord extends BaseActiveRecord } catch (\Exception $e) { $transaction->rollBack(); throw $e; + } catch (\Throwable $e) { + $transaction->rollBack(); + throw $e; } } diff --git a/framework/db/Connection.php b/framework/db/Connection.php index 506431bac1..c7906a0ef4 100644 --- a/framework/db/Connection.php +++ b/framework/db/Connection.php @@ -420,7 +420,7 @@ class Connection extends Component * Use 0 to indicate that the cached data will never expire. * @param \yii\caching\Dependency $dependency the cache dependency associated with the cached query results. * @return mixed the return result of the callable - * @throws \Exception if there is any exception during query + * @throws \Exception|\Throwable if there is any exception during query * @see enableQueryCache * @see queryCache * @see noCache() @@ -435,6 +435,9 @@ class Connection extends Component } catch (\Exception $e) { array_pop($this->_queryCacheInfo); throw $e; + } catch (\Throwable $e) { + array_pop($this->_queryCacheInfo); + throw $e; } } @@ -457,7 +460,7 @@ class Connection extends Component * @param callable $callable a PHP callable that contains DB queries which should not use query cache. * The signature of the callable is `function (Connection $db)`. * @return mixed the return result of the callable - * @throws \Exception if there is any exception during query + * @throws \Exception|\Throwable if there is any exception during query * @see enableQueryCache * @see queryCache * @see cache() @@ -472,6 +475,9 @@ class Connection extends Component } catch (\Exception $e) { array_pop($this->_queryCacheInfo); throw $e; + } catch (\Throwable $e) { + array_pop($this->_queryCacheInfo); + throw $e; } } @@ -671,7 +677,7 @@ class Connection extends Component * @param callable $callback a valid PHP callback that performs the job. Accepts connection instance as parameter. * @param string|null $isolationLevel The isolation level to use for this transaction. * See [[Transaction::begin()]] for details. - * @throws \Exception + * @throws \Exception|\Throwable if there is any exception during query. In this case the transaction will be rolled back. * @return mixed result of callback function */ public function transaction(callable $callback, $isolationLevel = null) @@ -689,6 +695,11 @@ class Connection extends Component $transaction->rollBack(); } throw $e; + } catch (\Throwable $e) { + if ($transaction->isActive && $transaction->level === $level) { + $transaction->rollBack(); + } + throw $e; } return $result; diff --git a/framework/db/Migration.php b/framework/db/Migration.php index 7b5a4e1678..b642b66cbb 100644 --- a/framework/db/Migration.php +++ b/framework/db/Migration.php @@ -95,15 +95,16 @@ class Migration extends Component implements MigrationInterface try { if ($this->safeUp() === false) { $transaction->rollBack(); - return false; } $transaction->commit(); } catch (\Exception $e) { - echo 'Exception: ' . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n"; - echo $e->getTraceAsString() . "\n"; + $this->printException($e); + $transaction->rollBack(); + return false; + } catch (\Throwable $e) { + $this->printException($e); $transaction->rollBack(); - return false; } @@ -123,21 +124,31 @@ class Migration extends Component implements MigrationInterface try { if ($this->safeDown() === false) { $transaction->rollBack(); - return false; } $transaction->commit(); } catch (\Exception $e) { - echo 'Exception: ' . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n"; - echo $e->getTraceAsString() . "\n"; + $this->printException($e); + $transaction->rollBack(); + return false; + } catch (\Throwable $e) { + $this->printException($e); $transaction->rollBack(); - return false; } return null; } + /** + * @param \Throwable|\Exception $e + */ + private function printException($e) + { + echo 'Exception: ' . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n"; + echo $e->getTraceAsString() . "\n"; + } + /** * This method contains the logic to be executed when applying this migration. * This method differs from [[up()]] in that the DB logic implemented here will diff --git a/framework/db/Transaction.php b/framework/db/Transaction.php index d2877163bb..9f4e9da1ab 100644 --- a/framework/db/Transaction.php +++ b/framework/db/Transaction.php @@ -25,7 +25,7 @@ use yii\base\InvalidConfigException; * $connection->createCommand($sql2)->execute(); * //.... other SQL executions * $transaction->commit(); - * } catch (\Exception $e) { + * } catch (\Exception $e) { // replace \Exception with \Throwable when you are using PHP 7 * $transaction->rollBack(); * throw $e; * }