Merge pull request #13217 from yiisoft/throwable

Catch `\Throwable` in critical places
This commit is contained in:
Dmitry Naumenko
2016-12-18 19:53:27 +02:00
committed by GitHub
7 changed files with 73 additions and 16 deletions

View File

@ -636,9 +636,16 @@ try {
} catch(\Exception $e) { } catch(\Exception $e) {
$transaction->rollBack(); $transaction->rollBack();
throw $e; throw $e;
} catch(\Throwable $e) {
$transaction->rollBack();
throw $e;
} }
``` ```
> Note: in the above code we have two catch-blocks for compatibility
> with PHP 5.x and PHP 7.x. `\Exception` implements the [`\Throwable` interface](http://php.net/manual/en/class.throwable.php)
> since PHP 7.0, so you can skip the part with `\Exception` if your app uses only PHP 7.0 and higher.
The second way is to list the DB operations that require transactional support in the [[yii\db\ActiveRecord::transactions()]] The second way is to list the DB operations that require transactional support in the [[yii\db\ActiveRecord::transactions()]]
method. For example, method. For example,

View File

@ -328,18 +328,17 @@ The above code is equivalent to the following, which gives you more control abou
```php ```php
$db = Yii::$app->db; $db = Yii::$app->db;
$transaction = $db->beginTransaction(); $transaction = $db->beginTransaction();
try { try {
$db->createCommand($sql1)->execute(); $db->createCommand($sql1)->execute();
$db->createCommand($sql2)->execute(); $db->createCommand($sql2)->execute();
// ... executing other SQL statements ... // ... executing other SQL statements ...
$transaction->commit(); $transaction->commit();
} catch(\Exception $e) { } catch(\Exception $e) {
$transaction->rollBack(); $transaction->rollBack();
throw $e;
} catch(\Throwable $e) {
$transaction->rollBack();
throw $e; throw $e;
} }
``` ```
@ -352,6 +351,10 @@ will be triggered and caught, the [[yii\db\Transaction::rollBack()|rollBack()]]
the changes made by the queries prior to that failed query in the transaction. `throw $e` will then re-throw the the changes made by the queries prior to that failed query in the transaction. `throw $e` will then re-throw the
exception as if we had not caught it, so the normal error handling process will take care of it. exception as if we had not caught it, so the normal error handling process will take care of it.
> Note: in the above code we have two catch-blocks for compatibility
> with PHP 5.x and PHP 7.x. `\Exception` implements the [`\Throwable` interface](http://php.net/manual/en/class.throwable.php)
> since PHP 7.0, so you can skip the part with `\Exception` if your app uses only PHP 7.0 and higher.
### Specifying Isolation Levels <span id="specifying-isolation-levels"></span> ### Specifying Isolation Levels <span id="specifying-isolation-levels"></span>
@ -424,12 +427,18 @@ try {
} catch (\Exception $e) { } catch (\Exception $e) {
$innerTransaction->rollBack(); $innerTransaction->rollBack();
throw $e; throw $e;
} catch (\Throwable $e) {
$innerTransaction->rollBack();
throw $e;
} }
$outerTransaction->commit(); $outerTransaction->commit();
} catch (\Exception $e) { } catch (\Exception $e) {
$outerTransaction->rollBack(); $outerTransaction->rollBack();
throw $e; throw $e;
} catch (\Throwable $e) {
$outerTransaction->rollBack();
throw $e;
} }
``` ```
@ -573,6 +582,9 @@ try {
} catch(\Exception $e) { } catch(\Exception $e) {
$transaction->rollBack(); $transaction->rollBack();
throw $e; throw $e;
} catch(\Throwable $e) {
$transaction->rollBack();
throw $e;
} }
``` ```

View File

@ -59,7 +59,7 @@ Yii Framework 2 Change Log
- Enh #12145: Added `beforeCacheResponse` and `afterRestoreResponse` to `yii\filters\PageCache` to be more easily extendable (sergeymakinen) - 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 #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 #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 #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 #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) - Enh #12732: Added `is_dir()` validation to `yii\helpers\BaseFileHelper::findFiles()` method (zalatov, silverfire)

View File

@ -439,6 +439,9 @@ class ActiveRecord extends BaseActiveRecord
} catch (\Exception $e) { } catch (\Exception $e) {
$transaction->rollBack(); $transaction->rollBack();
throw $e; throw $e;
} catch (\Throwable $e) {
$transaction->rollBack();
throw $e;
} }
} }
@ -545,6 +548,9 @@ class ActiveRecord extends BaseActiveRecord
} catch (\Exception $e) { } catch (\Exception $e) {
$transaction->rollBack(); $transaction->rollBack();
throw $e; throw $e;
} catch (\Throwable $e) {
$transaction->rollBack();
throw $e;
} }
} }
@ -585,6 +591,9 @@ class ActiveRecord extends BaseActiveRecord
} catch (\Exception $e) { } catch (\Exception $e) {
$transaction->rollBack(); $transaction->rollBack();
throw $e; throw $e;
} catch (\Throwable $e) {
$transaction->rollBack();
throw $e;
} }
} }

View File

@ -420,7 +420,7 @@ class Connection extends Component
* Use 0 to indicate that the cached data will never expire. * 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. * @param \yii\caching\Dependency $dependency the cache dependency associated with the cached query results.
* @return mixed the return result of the callable * @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 enableQueryCache
* @see queryCache * @see queryCache
* @see noCache() * @see noCache()
@ -435,6 +435,9 @@ class Connection extends Component
} catch (\Exception $e) { } catch (\Exception $e) {
array_pop($this->_queryCacheInfo); array_pop($this->_queryCacheInfo);
throw $e; 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. * @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)`. * The signature of the callable is `function (Connection $db)`.
* @return mixed the return result of the callable * @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 enableQueryCache
* @see queryCache * @see queryCache
* @see cache() * @see cache()
@ -472,6 +475,9 @@ class Connection extends Component
} catch (\Exception $e) { } catch (\Exception $e) {
array_pop($this->_queryCacheInfo); array_pop($this->_queryCacheInfo);
throw $e; 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 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. * @param string|null $isolationLevel The isolation level to use for this transaction.
* See [[Transaction::begin()]] for details. * 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 * @return mixed result of callback function
*/ */
public function transaction(callable $callback, $isolationLevel = null) public function transaction(callable $callback, $isolationLevel = null)
@ -689,6 +695,11 @@ class Connection extends Component
$transaction->rollBack(); $transaction->rollBack();
} }
throw $e; throw $e;
} catch (\Throwable $e) {
if ($transaction->isActive && $transaction->level === $level) {
$transaction->rollBack();
}
throw $e;
} }
return $result; return $result;

View File

@ -95,15 +95,16 @@ class Migration extends Component implements MigrationInterface
try { try {
if ($this->safeUp() === false) { if ($this->safeUp() === false) {
$transaction->rollBack(); $transaction->rollBack();
return false; return false;
} }
$transaction->commit(); $transaction->commit();
} catch (\Exception $e) { } catch (\Exception $e) {
echo 'Exception: ' . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n"; $this->printException($e);
echo $e->getTraceAsString() . "\n"; $transaction->rollBack();
return false;
} catch (\Throwable $e) {
$this->printException($e);
$transaction->rollBack(); $transaction->rollBack();
return false; return false;
} }
@ -123,21 +124,31 @@ class Migration extends Component implements MigrationInterface
try { try {
if ($this->safeDown() === false) { if ($this->safeDown() === false) {
$transaction->rollBack(); $transaction->rollBack();
return false; return false;
} }
$transaction->commit(); $transaction->commit();
} catch (\Exception $e) { } catch (\Exception $e) {
echo 'Exception: ' . $e->getMessage() . ' (' . $e->getFile() . ':' . $e->getLine() . ")\n"; $this->printException($e);
echo $e->getTraceAsString() . "\n"; $transaction->rollBack();
return false;
} catch (\Throwable $e) {
$this->printException($e);
$transaction->rollBack(); $transaction->rollBack();
return false; return false;
} }
return null; 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 contains the logic to be executed when applying this migration.
* This method differs from [[up()]] in that the DB logic implemented here will * This method differs from [[up()]] in that the DB logic implemented here will

View File

@ -28,9 +28,16 @@ use yii\base\InvalidConfigException;
* } catch (\Exception $e) { * } catch (\Exception $e) {
* $transaction->rollBack(); * $transaction->rollBack();
* throw $e; * throw $e;
* } catch (\Throwable $e) {
* $transaction->rollBack();
* throw $e;
* } * }
* ``` * ```
* *
* > Note: in the above code we have two catch-blocks for compatibility
* > with PHP 5.x and PHP 7.x. `\Exception` implements the [`\Throwable` interface](http://php.net/manual/en/class.throwable.php)
* > since PHP 7.0, so you can skip the part with `\Exception` if your app uses only PHP 7.0 and higher.
*
* @property bool $isActive Whether this transaction is active. Only an active transaction can [[commit()]] * @property bool $isActive Whether this transaction is active. Only an active transaction can [[commit()]]
* or [[rollBack()]]. This property is read-only. * or [[rollBack()]]. This property is read-only.
* @property string $isolationLevel The transaction isolation level to use for this transaction. This can be * @property string $isolationLevel The transaction isolation level to use for this transaction. This can be