Há várias maneiras de fazer transações no CakePHP. Aqui mostrarei uma delas que é o uso da função saveAll().
Vou exemplificar o seu uso com 2 modelos relacionados.
Imagine que estamos querendo construir um tipo de CRM. Nós teremos o modelo da Companhia, que guarda informações genéricas sobre a empresa. A Companhia tem muitas (hasMany) Contas, que irá guardar as informações relativas aos vários usuários que acessam o CRM.
Primeiro vamos criar as tabelas:
CREATE TABLE `companhias` ( `id` int(11) NOT NULL auto_increment PRIMARY KEY, `nome` varchar(200) NOT NULL, `descricao` varchar(200) NOT NULL, `localizacao` varchar(200) NOT NULL, `created` datetime NOT NULL );
CREATE TABLE `contas` ( `id` INT NOT NULL auto_increment PRIMARY KEY, `companhia_id` int(11) NOT NULL, `nome` VARCHAR( 200 ) NOT NULL, `usuario` VARCHAR( 200 ) NOT NULL, `email` VARCHAR( 200 ) NOT NULL, `created` DATETIME NOT NULL );
Depois vamos criar nossos modelos:
class Companhia extends AppModel {
public $hasMany= array('Conta');
public $validate = array(
'nome' => array('rule' => array('notEmpty')),
'descricao' => array('rule' => array('notEmpty'))
);
}
class Conta extends AppModel {
public $belongsTo = array('Companhia');
public $validate = array(
'nome' => array('rule' => 'notEmpty'),
'usuario' => array('rule' => 'notEmpty'),
'email' => array('rule' => 'email')
);
}
Como se pode ver, os modelos são bem simples, apenas adicionamos algumas validações e o suficiente para os propósitos deste exemplo.
Agora vamos criar o controlador da Companhia, que por hora ficará em branco:
class CompanhiaController extends AppController {
//
}
Agora que temos nossos modelos e um controlador, o próximo passo é criar algum formulário onde algum usuário do CRM irá cadastrar uma empresa e a primeira conta dela ao mesmo tempo. É aí que entra o saveAll(), porque ele nos permite salvar os dois modelos sem esforço.
Então vamos construir um formulário que nos permita criar a Companhia e a Conta (crie um arquivo chamado /companhias/add.ctp):
echo $form->create();
echo $form->input('Companhia.nome', array('label'=>'Nome da Empresa'));
echo $form->input('Companhia.descricao');
echo $form->input('Companhia.localizacao');
echo $form->input('Conta.0.nome', array('label'=>'Nome da Conta'));
echo $form->input('Conta.0.usuario');
echo $form->input('Conta.0.email');
echo $form->end('Add');
Vamos analisar o que temos aqui. Nós consideramos a Companhia para ser nosso modelo principal, portanto o formulário irá por padrão submeter para a ação de adicionar (add) do controlador da Companhialler (i.e. /companhias/add/).
Observe bem o modo como foi nomeado os campos do formulário do modelo Conta. Se a Companhia é nosso modelo principal, o saveAll() irá esperar que os dados de um modelo relacionado (Conta) cheguem num formato específico.
E tendo o Conta.0.nomeDoCampo é exatamente o que precisamos (isso só é verdadeiro para o relacionamento hasMany, para o hasOne os campos devem seguir o padrão Conta.nomeDoCampo).
Agora, no controlador Companhias nós podemos criar a ação add():
function add() {
if(!empty($this->data)) {
$this->Companhia->saveAll($this->data, array('validate'=>'first'));
}
}
É fácil ou não é?
Baseado no artigo em inglês: http://nuts-and-bolts-of-cakephp.com/2008/08/01/practical-use-of-saveall-part-1-working-with-multiple-models/