CakePHP: inserindo dados em relacionamento de dois níveis de hasOne

Recentemente eu publiquei um mini tutorial mostrando como salvar nas duas tabelas, quando possui um relacionamento hasOne entre dois Models/tabela. Porém quando há o seguinte caso:

Model1 hasOne Model2
Model2 hasOne Model3

A maneira que eu falei não funciona, pois o método saveAll possui apenas um nível de recursão. A partir disso, eu adicionarei apenas mais um relacionamento no exemplo anterior, copiando muito do que escrevi e alterando as partes necessárias para que ao enviar um form, as três tabelas sejam salvas.

CREATE TABLE IF NOT EXISTS cidades (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    endereco_id INT UNSIGNED NOT NULL,
    nome VARCHAR(60),
    descricao VARCHAR(200),
    PRIMARY KEY(id)
) ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS enderecos (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    funcionario_id INT UNSIGNED NOT NULL,
    rua VARCHAR(60),
    numero VARCHAR(15),
    cep VARCHAR(8),
    bairro VARCHAR(60),
    estado VARCHAR(2),
    pais VARCHAR(30),
    PRIMARY KEY (id)
) ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS pessoas (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    nome VARCHAR(60) NOT NULL,
    email VARCHAR(60) NOT NULL,
    cpf VARCHAR(11) NOT NULL,
    senha VARCHAR(20) NOT NULL,
    PRIMARY KEY (id)
) ENGINE = InnoDB;

A partir dai, podemos partir para o Cake. O CakePHP reconhece uma foreign key automaticamente, caso você siga o padrão de nomenclatura estipulado. No caso, uma chave estrangeira deverá ser o padrão: nome_da_entidade + _id.
Então, para termo algum consistente em mãos rapidamente, vamos utilizar o scaffold para visualizar o que aconteceu nesta brincadeira:

O controller

class PessoasController extends AppController {
     var $helpers = array ('Html', 'Form');
     var $name = "Pessoas";
     var $scaffold;
}

O model de Pessoa:

class Pessoa extends AppModel {
     var $name = "Pessoa";
     var $hasOne = "Endereco";
}

O Controller do Endereço:

class EnderecosController extends AppController {
     var $helpers = array ('Html', 'Form');
     var $name = "Enderecos";
     var $scaffold;
}

E o Model de Endereço:

class Endereco extends AppModel {
 	var $name = "Endereco";
 	var $hasOne = "Cidade";
}

O model de cidades:

class Cidade extends AppModel {
 	var $name = "Cidade";
}

E o controller de cidades:

class CidadesController extends AppController {
     var $helpers = array ('Html', 'Form');
     var $name = "Cidades";
     var $scaffold;
}

Com este código, teremos um CRUD, ontem caso entre em pessoa/add, aparecerá uma tabela listando todas as pessoas cadastradas, além das opções para adicionar uma nova pessoa E para adicionar um endereço.
Ao entrar em adicionar um endereço, você verá que há uma lista com os ids das pessoas cadastradas, e você atrelará o endereço a este id.

Mas ai fica a pergunta, o que devo fazer para adicionar de uma única vez um usuário e o seu respectivo endereço?! Como nem tudo são rosas, e as aplicações não são construídas apenas com scaffolding, será necessário realizar algumas alterações. No Cook Book do Cake, há uma parte dedicada a esta questão que pode ser conferida aqui.

A principal diferença entre construir um form normal atrelado a um único model e um form com dados de dois models que estão relacionados é que ao utilizar o input do helper Html, você adicionará o nome do model antes de cada campo.

// provavelmente na view add, ou o equivalente para adicionar a pessoa

echo $this->Form->create('Pessoa', array('action' => 'add'));
echo $this->Form->input('Pessoa.nome');
echo $this->Form->input('Pessoa.cpf');
echo $this->Form->input('Pessoa.email');
echo $this->Form->input('Pessoa.senha');
echo $this->Form->input('Endereco.rua');
echo $this->Form->input('Endereco.numero');
echo $this->Form->input('Endereco.cep');
echo $this->Form->input('Endereco.bairro');
echo $this->Form->input('Endereco.estado');
echo $this->Form->input('Endereco.pais');
echo $this->Form->input('Cidade.nome');
echo $this->Form->input('Cidade.descricao');
echo $this->Form->end('Confirmar cadastro');

E o método add (ou equivalente) no Controller de Pessoa:

function add() {
    if (!empty($this->data)) {
	$pessoa= $this->Pessoa->save($this->data);
			
			if (!empty($pessoa)) {
				$this->data['Endereco']['pessoa_id'] = $this->Pessoa->id;
				$endereco = $this->Pessoa->Endereco->save($this->data);
				
				if (!empty($endereco)) {
					$this->data['Cidade']['endereco_id'] = $this->Pessoa->Endereco->id;
					$resultado = $this->Pessoa->Endereco->Cidade->save($this->data);
					
					if ($resultado)
						$this->Session->setFlash('Cadastrado com sucesso');
					
				}
			} 
    }
}

Bem, por hoje é só 😉

Anúncios

7 comentários sobre “CakePHP: inserindo dados em relacionamento de dois níveis de hasOne

  1. Mas e se eu precisar inserir mais de um endereço em uma cidade, precisarei pegar ids diferentes de endereço e salvar em endereco_id para cada registro na tabela cidades, só que pra mim sempre pega apenas uma id, a última inserida ;/

    $this->Pessoa->Endereco->id; -> preciso pegar estas ids, se eu inserir mais de um endereço pra uma cidade.

    $this->data['Cidade']['endereco_id'] = $this->Pessoa->Endereco->id;
    $resultado = $this->Pessoa->Endereco->Cidade->save($this->data);
  2. Gostei do tutorial parabéns!
    Agora pra editar os dados de enderecos e cidades direto no edit de pessoas, eu sei que posso usar o form do add,
    e o function edit() do controller da entidade pessoas como ficaria, no caso aqui eu fiz um exercicio com uma entidade (pessoa) e varias entidades, (endereco), ( cidade), (bairro), (sexo ), ( filhacao) tudo funciono mas eu queria editar todos os dados diretamente no form da edit de pessoas .
    Vou da um pesquisada pra vê se encontro alguma coisa valeu abraços porDT.

  3. Cara como eu converteria um campo em uma variavel pra concatenar ou contar, exemplo na tabela pessoas o campo nome vem com array [nome] gostaria de ter esse campo como uma variavel $nome += 1; , consegui isso pelo model fazendo um um virtualField SUM, só que no index da view perco a paginação.

  4. Rafael, você mostrou exatamente o que eu estou fazendo!
    Só preciso validar este formulário com os models relacionados.

    Como faço?

  5. Isso não é mais necessário no cake 2.x, basta usar o método
    $this->pessoa->saveAll($this->request->data)
    que ele salva todas as tabelas relacionadas.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s