diff --git a/wire/core/FieldtypeMulti.php b/wire/core/FieldtypeMulti.php index c6c50b93..c1d56709 100644 --- a/wire/core/FieldtypeMulti.php +++ b/wire/core/FieldtypeMulti.php @@ -208,8 +208,10 @@ abstract class FieldtypeMulti extends Fieldtype { public function ___savePageField(Page $page, Field $field) { if(!$page->id || !$field->id) return false; - + + /** @var WireDatabasePDO $database */ $database = $this->wire('database'); + $useTransaction = $database->allowTransaction(); $values = $page->get($field->name); $schema = array(); @@ -227,11 +229,19 @@ abstract class FieldtypeMulti extends Fieldtype { $values = $this->sleepValue($page, $field, $values); $table = $database->escapeTable($field->table); $page_id = (int) $page->id; + + // use transaction when possible + if($useTransaction) $database->beginTransaction(); - // since we don't manage IDs of existing values for multi fields, we delete the existing data and insert all of it again - $query = $database->prepare("DELETE FROM `$table` WHERE pages_id=:page_id"); // QA - $query->bindValue(":page_id", $page_id, \PDO::PARAM_INT); - $query->execute(); + try { + // since we don't manage IDs of existing values for multi fields, we delete the existing data and insert all of it again + $query = $database->prepare("DELETE FROM `$table` WHERE pages_id=:page_id"); // QA + $query->bindValue(":page_id", $page_id, \PDO::PARAM_INT); + $query->execute(); + } catch(\Exception $e) { + if($useTransaction) $database->rollBack(); + throw $e; + } if(count($values)) { @@ -284,21 +294,24 @@ abstract class FieldtypeMulti extends Fieldtype { $sort++; } - $sql = rtrim($sql, ", "); - $query = $database->prepare($sql); try { + $query = $database->prepare(rtrim($sql, ", ")); $result = $query->execute(); } catch(\Exception $e) { + if($useTransaction) $database->rollBack(); if($this->wire('config')->allowExceptions) throw $e; // throw original $msg = $e->getMessage(); if($this->wire('config')->debug && $this->wire('config')->advanced) $msg .= "\n$sql"; throw new WireException($msg); // throw WireException } - return $result; + } else { + $result = true; } - return true; + if($useTransaction) $database->commit(); + + return $result; } /** diff --git a/wire/core/WireDatabasePDO.php b/wire/core/WireDatabasePDO.php index b3264a86..bce1591e 100644 --- a/wire/core/WireDatabasePDO.php +++ b/wire/core/WireDatabasePDO.php @@ -332,7 +332,7 @@ class WireDatabasePDO extends Wire implements WireDatabase { * */ public function inTransaction() { - return $this->pdo()->inTransaction(); + return (bool) $this->pdo()->inTransaction(); } /** @@ -361,6 +361,22 @@ class WireDatabasePDO extends Wire implements WireDatabase { return strtoupper($engine) === 'INNODB'; } + /** + * Allow a new transaction to begin right now? (i.e. supported and not already in one) + * + * Returns combined result of supportsTransaction() === true and inTransaction() === false. + * + * #pw-group-PDO + * + * @param string $table Optional table that transaction will be for + * @return bool + * @since 3.0.140 + * + */ + public function allowTransaction($table = '') { + return $this->supportsTransaction($table) && !$this->inTransaction(); + } + /** * Commits a transaction *