Поддерживает ли CakePHP транзакции по нескольким моделям? - PullRequest
5 голосов
/ 30 августа 2011

Я пишу приложение, которое поддерживает несколько единиц измерения. В редких случаях, когда пользователь хотел изменить свою систему измерения, мне нужно выполнить запрос, который применяет множитель для масштабирования каждого столбца единицы в приложении к правильной системе измерения. Чтобы убедиться, что все данные остаются нормальными в случае, если что-то в этой операции идет не так, мне нужно выполнить запросы внутри транзакции.

Возможно ли в Cake выполнить транзакцию, которая содержит запросы, охватывающие несколько моделей?

Все, что я нашел до сих пор, это DataSource :: begin / commit / rollback () , но он поддерживает запросы только к отдельным моделям.

1 Ответ

5 голосов
/ 30 августа 2011

да, это так.У меня есть это в моей модели приложения, чтобы сделать транзакции легкими.

https://github.com/infinitas/infinitas/blob/dev/Model/AppModel.php#L677

    /**
     * @brief wrapper for transactions
     *
     * Allow you to easily call transactions manually if you need to do saving
     * of lots of data, or just nested relations etc.
     *
     * @code
     *  // start a transaction
     *  $this->transaction();
     *
     *  // rollback if things are wrong (undo)
     *  $this->transaction(false);
     *
     *  // commit the sql if all is good
     *  $this->transaction(true);
     * @endcode
     *
     * @access public
     *
     * @param mixed $action what the command should do
     *
     * @return see the methods for tranasactions in cakephp dbo
     */
    public function transaction($action = null) {
        $this->__dataSource = $this->getDataSource();
        $return = false;
        if($action === null) {
            $return = $this->__dataSource->begin($this);
        } else if($action === true) {
            $return = $this->__dataSource->commit($this);
        } else if($action === false) {
            $return = $this->__dataSource->rollback($this);
        }
        return $return;
    }

тогда вы можете сделать что-то вроде этого:

$saved = true;
$this->transaction();
$saved = $saved && $this->save($data);
$saved = $saved && $this->SomeOtherModel->save($data2);
$saved = $saved && $this->AnotherModel->save($data3);

if($saved){
$this->transaction(true);
    return $this->id;
}
$this->transaction(false);
return false;

вы также можетеделать более сложные вещи, такие как следующее:

function save1(){

    $saved = true;
    $this->transaction();
    $saved = $saved && $this->save($data);
    $saved = $saved && $this->save2($data);


    if($saved){
        $this->transaction(true);
        return $this->id;
    }

    $this->transaction(false);
    return false;
}

торт не поддерживает вложенные транзакции, но вы можете сортировать их как поддельные

// this will use transactions if its called directly, but will allow a calling method to

// create and manage the transaction.

function save2($data){
    $saved = true;
    $transaction = $this->transaction(); // will only be true if not already started
    $saved = $saved && $this->save($data);

    if($transaction){ // if it was started here, finish it
        if($saved){
            $this->transaction(true);
            return true;
        }

        $this->transaction(false);
        return false;
    }

    return $saved; // return just the status so the other model will finish the transaction
}

просто чтобы прояснить, вы можете делать что-то вроде ClassRegistry :: init ('SomeRandomModel') -> save2 ().транзакции не ограничены текущей моделью или родственными моделями.это для любой модели.

...