CRUD de duas Tabelas

Olá pessoal, segue abaixo o exemplo de duas tabelas de meu banco de dados, (é apenas um exemplo):

CREATE TABLE IF NOT EXISTS pessoa (

idpessoa int(11) NOT NULL AUTO_INCREMENT,

nome varchar(45) NOT NULL,

idtipopessoa int(11) NOT NULL,

PRIMARY KEY (idpessoa)

)

CREATE TABLE IF NOT EXISTS email (

idemail int(11) NOT NULL AUTO_INCREMENT,

idpessoa int(11) NOT NULL,

email varchar(100) NOT NULL,

PRIMARY KEY (idemail),

KEY idpessoa (idpessoa)

)

ALTER TABLE email

ADD CONSTRAINT email_ibfk_1 FOREIGN KEY (idpessoa) REFERENCES pessoa (idpessoa) ON DELETE NO ACTION ON UPDATE NO ACTION;

Preciso criar um CRUD para esta estrutura, mas preciso que os campos da tabela pessoa e e-mail estejam juntos no mesmo form. Ou seja, na tela de cadastro (insert ou update) o usuário precisa ver os seguintes campos no formulário: Nome, Tipo de pessoa (que pega de um dropdown de outra tabela, mas que já esta ok) e e-mail (que esta na tabela de nome ‘email’).

Alguém sabe como posso fazer isso e pode me ajudar? Obrigado.




//nas relations no seu segundo model 

return array(

			'pessoa'=>array(self::BELONG_TO, 'Pessoa', 'idpessoa'),

		);

//nas relations do primeiro model 

return  array(

			'email'=>array(self::HAS_ONE, 'Email', 'idpessoa'),

		);



ae pra usar faça algo como o seguinte:




$pessoal_model->email->email;

//ou

$email_model->pessoa->nome;



E ao gerar o crud pelo Gii ou Console o form vai aparecer com todos os campos? Não terei que fazer nada na View e nem no Controller?

Você aind aprecisa especificar os campos que deseja mostrar na view, e no formulario na hora de salvar deve ajustar o codigo

O codigo que passei estabelece relação estre as duas tabelas, assim na hora que você usar as variaveis definidas em relations(), essa variavel vai conter os dados gerados pelo relacionamento que passei no codigo acima

De uma olhada no manual de relacionamentos para maiores explicações

Na verdade meu problema é o mesmo deste Topico,

http://www.yiiframework.com/forum/index.php?/topic/11879-personalizando-tela-de-cadastro-no-yii-com-select-radio-e-checkbox/page__st__20__p__77093#entry77093

com ajuda dele consegui resolver com relação ao Insert, mas já com relação ao Update não tive sucesso ainda.

Alguém pode me dar uma dica?

Acredito que o problema esteja no controller, vejam como penso em fazer




public function actionUpdate($id)

{

        $model=$this->loadModel($id);

        $usuario = new Usuario;

        $email = new Email;

        $telefone = new Telefone;


        //$usuario = Usuario::model()->find(array('idpessoa'=>$id));

        //$email = Email::model()->find(array('idpessoa'=>$id));

        //$telefone = Telefone::model()->find(array('idpessoa'=>$id));


        // Uncomment the following line if AJAX validation is needed

        $this->performAjaxValidation(array($model,$usuario,$email,$telefone));


        if(isset($_POST['Pessoa']))

        {

            $model->attributes=$_POST['Pessoa'];

            $model->save();

        }


        if (isset($_POST['Usuario']))

        {

            $usuario->attributes=$_POST['Usuario'];

            $usuario->save();

        }


        if (isset($_POST['Email']))

        {

            $email->attributes=$_POST['Email'];

            $email->save();

        }


        if (isset($_POST['Telefone']))

        {

            $telefone->attributes=$_POST['Telefone'];

            $telefone->save();

        }


        if( isset($_POST['Pessoa']) || isset($_POST['Usuario']) || isset($_POST['Email']) || isset($_POST['Telefone']))

        {

            $this->redirect(array('view','id'=>$model->idpessoa));

        }


        $this->render('update',array(

                'model'=>$model,

                'usuario'=>$usuario,

                'email'=>$email,

                'telefone'=>$telefone,

        ));

}



Acredito que tenha que popular o objeto de cada tabela conforme tentei fazer lá no inicio do código, mas acredito que daquela forma esta errado.

Para a tabela principal ele utiliza a linha abaixo para popular o model principal.




$model=$this->loadModel($id);



Nas linhas comentadas tentei popular os outros models, mas não sei se esta certo.

Alguém pode me ajudar?

se entende um pouco de ingles este topico vai ajudar

Olá Gustavo, na verdade não ajuda não, esta parte do ‘actionCreate’ eu consegui fazer da seguinte forma:




public function actionCreate()

{

        $model = new Pessoa;

        $usuario = new Usuario;

        $email = new Email;

        $telefone = new Telefone;


        // Uncomment the following line if AJAX validation is needed

        $this->performAjaxValidation(array($model,$usuario,$email,$telefone));


        if( isset($_POST['Pessoa']) && isset($_POST['Usuario']) && isset($_POST['Email']) && isset($_POST['Telefone']))

        {

                $model->attributes=$_POST['Pessoa'];

                $usuario->attributes=$_POST['Usuario'];

                $email->attributes=$_POST['Email'];

                $telefone->attributes=$_POST['Telefone'];


                if ($model->validate())

                {

                    $model->save();

                }

                if ($usuario->validate())

                {

                    $usuario->idpessoa = $model->idpessoa;

                    $usuario->senha = md5($usuario->senha);

                    //$usuario->status = '1';

                    $usuario->save();

                }

                if ($email->validate())

                {

                    $email->idpessoa = $model->idpessoa;

                    $email->save();

                }

                if ($telefone->validate())

                {

                    $telefone->idpessoa = $model->idpessoa;

                    $telefone->save();

                }


                if ($model->validate() && $usuario->validate() && $email->validate() && $telefone->validate())

                {

                    $this->redirect(array('view','id'=>$model->idpessoa));

                }

        }


        $this->render('create',array(

                'model'=>$model,

                'usuario'=>$usuario,

                'email'=>$email,

                'telefone'=>$telefone,

        ));

}



Esta parte esta funcionando perfeitamente, estou com dificuldade para fazer é o Update, se alguém tiver algum artigo que me ajude ou souber de algum topico que faça algo parecido vai ajudar demais.

O meu ‘actionUpdate’ esta assim:




public function actionUpdate($id)

{

        $model=$this->loadModel($id);

        $usuario = new Usuario;

        $email = new Email;

        $telefone = new Telefone;


        //$usuario = Usuario::model()->find(array('idpessoa'=>$id));

        //$email = Email::model()->find(array('idpessoa'=>$id));

        //$telefone = Telefone::model()->find(array('idpessoa'=>$id));


        // Uncomment the following line if AJAX validation is needed

        $this->performAjaxValidation(array($model,$usuario,$email,$telefone));


        if(isset($_POST['Pessoa']))

        {

            $model->attributes=$_POST['Pessoa'];

            $model->save();

        }


        if (isset($_POST['Usuario']))

        {

            $usuario->attributes=$_POST['Usuario'];

            $usuario->save();

        }


        if (isset($_POST['Email']))

        {

            $email->attributes=$_POST['Email'];

            $email->save();

        }


        if (isset($_POST['Telefone']))

        {

            $telefone->attributes=$_POST['Telefone'];

            $telefone->save();

        }


        if( isset($_POST['Pessoa']) || isset($_POST['Usuario']) || isset($_POST['Email']) || isset($_POST['Telefone']))

        {

            $this->redirect(array('view','id'=>$model->idpessoa));

        }


        $this->render('update',array(

                'model'=>$model,

                'usuario'=>$usuario,

                'email'=>$email,

                'telefone'=>$telefone,

        ));

}



O meu problema acredito estar neste trecho:




public function actionUpdate($id)

{

        $model=$this->loadModel($id);

        $usuario = new Usuario;

        $email = new Email;

        $telefone = new Telefone;


        //$usuario = Usuario::model()->find(array('idpessoa'=>$id));

        //$email = Email::model()->find(array('idpessoa'=>$id));

        //$telefone = Telefone::model()->find(array('idpessoa'=>$id));



Preciso carregar o $usuario,$email e $telefone da mesma forma que foi carregado o $model na linha:




$model=$this->loadModel($id);



Ja testou o que vem na var $id ? talvez nao esteja vindo correto

Tambem me mostra a função loadModel

tambem seria uma boa fazer uma validação antes de redirecionar, algo como :

$valid=true;

em cada if algo como

$valid = $model->save() && $valid;

dae no final se valid for true é pq deu tudo certo, se for false deu algum erro no caminho

Bom, na verdade o $id esta retornando o valor correto sim, no formulário os unicos campos que são resgatados também são os relacionados ao $model, já os campos relacionados a $usuario,$email e $telefone vem em branco.

Ao editar todos os campos os unicos que alteram são os relacionados ao $model também.

Esta questão da validação realmente é importante, obrigado por ter lembrado, eu ia sem dúvidas me esquecer disso.

esta função loadModel foi criada pelo próprio Yii, acho que ela serve para carregar nos inputs os valores de cada campo a partir da busca do id, mas não tenho certeza, vou procurar sobre ela e colocar aqui.

Consegui fazer com que os campos do formulário venham todos preenchidos no update, ficou assim:





public function actionUpdate($id)

	{

		$model=$this->loadModel($id);


                $email = new Email;

                $telefone = new Telefone;

                $usuario = new Usuario;

                

                $email = Email::model()->find(array('condition'=>'idpessoa=:idpessoa','params'=>array(':idpessoa'=>$id)));

                $telefone = Telefone::model()->find(array('condition'=>'idpessoa=:idpessoa','params'=>array(':idpessoa'=>$id)));

                $usuario = Usuario::model()->find(array('condition'=>'idpessoa=:idpessoa','params'=>array(':idpessoa'=>$id)));

               




Apenas um campo não esta preenchido conforme recuperação no banco, é o campo da Cidade, mas deve ser pq fiz um dropdown dinamico que muda as cidades de acordo com a escolha do estado. Como estado não tem valor do banco preciso achar uma forma de fazer o dropdown dinâmico funcionar de forma reversa.

Gustavo, valeu pela força, com relação ao Update eu resolvi o problema, era pq eu tinha alterado o nome do campo para exibição no label no _form, o correto era alterar no attributeLabels() dentro do model de cada tabela.

Depois que fiz isso resolveu o problema.

Agora o único problema é para fazer resgatar o campo da cidade no Dropdown que fiz dinâmico, você ou alguém pode me dar um caminho para fazer com que a cidade cadastrada no banco apareça no update?

Algo como o seguinte:


echo CHtml::dropDownList('estado_id','', CHtml::listData(Estados::model()->findAll()),

 array(

   'ajax' => array(

    'type'=>'POST', //request type

    'url'=>CController::createUrl('controller/getcidades'), //url de pegar cidades.

    'replace'=>'#cidade_id', //onde colocar o resultado

 	//poderia ser 'update' ao inves de replace, ae você só retornaria os options nao todo o select

  )

); 

 

echo CHtml::dropDownList('cidade_id','', array());

e então faça uma action, algo como :




public function actionGetcidades()

{

    $model=Cidades::model();

    $data=$model->findAll('estado_id=:estado_id',array(':estado_id'=>(int) $_POST['estado_id']));

 

    echo CHtml::activeDropDownList($model,'cidade_id',CHtml::listData($data,'cidade_id','cidade_name'));

}



acredito que esta tudo certo apesar de ter escrito aqui no editor mesmo

També vou tentar fazer isso, já estou tentando, se eu conseguir eu mando aqui.

Olha só, meu código do dropdown esta funcionando e esta assim:

_form




<?php

$estado = Estado::model()->findAllEstado();

  echo CHtml::dropDownList('estado','', $estado,

  array(

  'empty' => 'Selecione um estado',

  'ajax' => array(

  'type'=>'POST',

  'url'=>CController::createUrl('pessoa/dynamiccities'),

  'update'=>'#idcidade', //Quando coloco replace ele mostra corretamente os campos só que saindo de dentro do dropdown.

)));


?>

    

<?php echo CHtml::dropDownList('idcidade','', array(), array('empty' => 'Selecione uma cidade')); ?>



action dentro do controller




public function actionDynamiccities()

{

    $idestado = $_POST['estado'];

    $data=Cidade::model()->findPorEstado($idestado);

    foreach($data as $value=>$name)

    {

        echo CHtml::tag('option',

                   array('value'=>$value),CHtml::encode($name),true);

    }


}



função findPorEstado que esta dentro do model Cidade




public function findPorEstado($idestado)

{

    //format models resulting using listData

    return $list = CHtml::listData($models = Cidade::model()->findAll(

            array(

                'condition'=>'idestado=:idestado',

                'params'=>array(':idestado'=>$idestado),

            )), 'idcidade', 'nom_cidade');

} //Fiz esta função só pq como vou ter que usar-la em varios lugares fica mais facil chamar-la.



Este é meu código do Dropdown, ele esta funcionando corretamente, mas sempre quando abro a tela de update ele aparece zerado, como se o usuário não tivesse informado nada, o que preciso é fazer com que os campos estado e cidade dos dropdowns já estejam preenchidos com o que o usuário salvou no banco, e o detalhe é que só sei o id da cidade, ou seja, só o id da cidade que esta no banco, mas na tabela de cidades eu tenho o campo idestado para saber de qual estado é cada cidade.

Penso que preciso recuberar este valor de idcidade, por ele achar o idestado da cidade que o usuário é, marcar no dropdown o estado que encontramos, e pegar também a cidade e marcar-la.

use relacionamento de tabela




//model

function relations(){

   return array(

   	'estado'=>array(self::BELONGS_TO,'Estado','estadoid');

   );

}

//pra usar

$cidade=Cidade::model()->findByPk(1);

$cidade->estado->nome;//nome do estado



Não entendi, mas vou tentar pensar nisso que vc disse.

em seu UserIdentity




function getCidade(){

   return $this->_model->idcidade;

}


/e pra buscar 


Yii::app()->user->cidade

/ou

Yii::app()->user->getCidade();




depois use relações como falei acima pra buscar o estado




$cidadeId=Yii::app()->user->cidade;

$cidade=Cidades::model()->findByPk($cidadeId);

$estado=$cidade->estado->id;



Agora entendi o que vc falou, é o seguinte, o ID do Estado e o ID da Cidade eu consegui recuperar, mas como faço para que o Dropdown fique com Selected no ID que eu recuperei?

nao tenho certeza, mas algo como




$form->dropDownList(

  $model,'cidade',$data,

  array(

       	array('options'=>array(

                     	Yii::app()->user->cidade=>array('selected'=>'selected')

      	)

   )

);



deve funcionar

Não deu, talvez fiz algo de errado pq não entendi esta logica. Tem alguma forma de fazer pelo controller com que o dropdown já venha com selected em determinado valor?