Ayuda Con 2 Modelos Para Un Solo Formulario

Tengo un formulario que trabaja con 2 modelos diferentes, en este caso serian solicitantes con los campos cedula, nombres, apellidos, direccion, telefono, fecha de nacimiento y solicitudes_sociales con los campos tipo de solicitus, fecha y descripcion, el problema se me presenta cuando registro todo el formulario ejemplo los datos de solicitante cedula=19956004, nombre= miguel apellido= lopez direccion=xxx, etc… y los datos de solicitudes tipo de solicitud= solicitud de salud fecha=hoy descripcion= solicitud de ayuda para donacion de sillas de ruedas. Luego de la explicación presento el problema que es le siguiente cuando una persona se presenta mas de 1 vez a realizar 1 solicitud se registra 2 veces la misma persona en la tabla solicitantes por supuesto con una solicitud diferente, que solución me proponen para resolver mi problema, de antemano muchas gracias.

aqui el codigo del formulario


<?php

/* @var $this SolicitudesSocialController */

/* @var $model SolicitudesSocial */

/* @var $form CActiveForm */

?>


<div class="form">


<?php 




$form=$this->beginWidget('CActiveForm', array(

	'id'=>'solicitudes-social-form',

	// Please note: When you enable ajax validation, make sure the corresponding

	// controller action is handling ajax validation correctly.

	// There is a call to performAjaxValidation() commented in generated controller code.

	// See class documentation of CActiveForm for details on this.

	'enableAjaxValidation'=>false,

)); 

if ($a->isNewRecord==false) {$b=Solicitantes::model()->findByPk($a->solicitantes_id); }

echo $form->errorSummary(array($a,$<img src='http://www.yiiframework.com/forum/public/style_emoticons/default/cool.gif' class='bbc_emoticon' alt='B)' />); 

?>


	<p class="note">Campos con <span class="required">*</span> son Obligatorios.</p>


	<div class="row">

		<?php echo $form->labelEx($b,'cedula'); ?>

		<?php echo $form->textField($b,'cedula',array('size'=>12,'maxlength'=>12));?>

		<?php echo $form->error($b,'cedula'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($b,'nombre'); ?>

		<?php echo $form->textField($b,'nombre',array('size'=>60,'maxlength'=>100)); ?>

		<?php echo $form->error($b,'nombre'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($b,'apellido'); ?>

		<?php echo $form->textField($b,'apellido',array('size'=>60,'maxlength'=>100)); ?>

		<?php echo $form->error($b,'apellido'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($b,'nacimiento'); ?>

		<?php echo $form->textField($b,'nacimiento'); ?>

		<?php echo $form->error($b,'nacimiento'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($b,'edad'); ?>

		<?php echo $form->textField($b,'edad'); ?>

		<?php echo $form->error($b,'edad'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($b,'sexo'); ?>

		<?php echo $form->textField($b,'sexo'); ?>

		<?php echo $form->error($b,'sexo'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($b,'direccion'); ?>

		<?php echo $form->textField($b,'direccion',array('size'=>60,'maxlength'=>255)); ?>

		<?php echo $form->error($b,'direccion'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($b,'numero de casa'); ?>

		<?php echo $form->textField($b,'numerocasa',array('size'=>15,'maxlength'=>15)); ?>

		<?php echo $form->error($b,'numerocasa'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($b,'telefono'); ?>

		<?php echo $form->textArea($b,'telefono',array('rows'=>6, 'cols'=>50)); ?>

		<?php echo $form->error($b,'telefono'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($b,'email'); ?>

		<?php echo $form->textField($b,'email',array('size'=>60,'maxlength'=>255)); ?>

		<?php echo $form->error($b,'email'); ?>

	</div>

    

    <div class="row">

		<?php echo $form->labelEx($b,'circuitos_id'); ?>

		<?php echo $form->dropDownList($b,'circuitos_id', CHtml::listData(Circuitos::model()->findAll(), 'id', 'nombre'),array('empty'=>'Seleccione un circuito')); ?>

		<?php echo $form->error($b,'circuitos_id'); ?>

	</div>

    

    <div class="row">

		<?php echo $form->labelEx($a,'tipo_solicitudes_id'); ?>

		<?php echo $form->textField($a,'tipo_solicitudes_id',array('size'=>60,'maxlength'=>100)); ?>

		<?php echo $form->error($a,'tipo_solicitudes_id'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($a,'departamentos_id'); ?>

		<?php echo $form->textField($a,'departamentos_id',array('size'=>60,'maxlength'=>100)); ?>

		<?php echo $form->error($a,'departamentos_id'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($a,'solicitantes_id'); ?>

		<?php echo $form->textField($a,'solicitantes_id',array('size'=>60,'maxlength'=>100)); ?>

		<?php echo $form->error($a,'solicitantes_id'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($a,'fecha'); ?>

		<?php echo $form->textField($a,'fecha'); ?>

		<?php echo $form->error($a,'fecha'); ?>

	</div>

    

    <div class="row">

		<?php echo $form->labelEx($b,'usuarios'); ?>

		<?php echo $form->textField($b,'usuarios_id'); ?>

		<?php echo $form->error($b,'usuarios_id'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($a,'descripcion'); ?>

		<?php echo $form->textArea($a,'descripcion',array('rows'=>6, 'cols'=>50)); ?>

		<?php echo $form->error($a,'descripcion'); ?>

	</div>


	<div class="row buttons">

		<?php echo CHtml::submitButton($a->isNewRecord ? 'Crear' : 'Guardar'); ?>

	</div>


<?php $this->endWidget(); ?>


</div><!-- form -->

aqui el codigo del modelo de solicitudes sociales


<?php


/**

 * This is the model class for table "solicitudes_social".

 *

 * The followings are the available columns in table 'solicitudes_social':

 * @property string $id

 * @property string $tipo_solicitudes_id

 * @property string $departamentos_id

 * @property string $solicitantes_id

 * @property string $fecha

 * @property string $descripcion

 */

class SolicitudesSocial extends CActiveRecord

{

	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'solicitudes_social';

	}

    

    /**

	 * @return string este pedazo lo puso miguel

	 */

	public function primaryKey()

	{

		return 'id';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('tipo_solicitudes_id, departamentos_id, solicitantes_id, fecha, descripcion', 'required'),

			array('tipo_solicitudes_id, departamentos_id, solicitantes_id', 'length', 'max'=>100),

			// The following rule is used by search().

			// @todo Please remove those attributes that should not be searched.

			array('id, tipo_solicitudes_id, departamentos_id, solicitantes_id, fecha, descripcion', 'safe', 'on'=>'search'),

		);

	}


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'ID',

			'tipo_solicitudes_id' => 'Tipo Solicitudes',

			'departamentos_id' => 'Departamentos',

			'solicitantes_id' => 'Solicitantes',

			'fecha' => 'Fecha',

			'descripcion' => 'Descripcion',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 *

	 * Typical usecase:

	 * - Initialize the model fields with values from filter form.

	 * - Execute this method to get CActiveDataProvider instance which will filter

	 * models according to data in model fields.

	 * - Pass data provider to CGridView, CListView or any similar widget.

	 *

	 * @return CActiveDataProvider the data provider that can return the models

	 * based on the search/filter conditions.

	 */

	public function search()

	{

		// @todo Please modify the following code to remove attributes that should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id,true);

		$criteria->compare('tipo_solicitudes_id',$this->tipo_solicitudes_id,true);

		$criteria->compare('departamentos_id',$this->departamentos_id,true);

		$criteria->compare('solicitantes_id',$this->solicitantes_id,true);

		$criteria->compare('fecha',$this->fecha,true);

		$criteria->compare('descripcion',$this->descripcion,true);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}


	/**

	 * Returns the static model of the specified AR class.

	 * Please note that you should have this exact method in all your CActiveRecord descendants!

	 * @param string $className active record class name.

	 * @return SolicitudesSocial the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}

}



Debes estructurar tu aplicación para que permita buscar a los solicitantes ya guardados antes de aceptar la solicitud. Si aparece el solicitante entonces se crea una solicitud a su nombre; de lo contrario se crea el solicitante y luego la solicitud. En el modelo del solicitante debe haber una relación HAS_MANY solicitudes y el el modelo de solicitud una relacion BELONGS_TO solicitante. Por supuesto el solicitante debe ser único en su tabla ya sea por nombre, cédula, etc.

Estoy muy claro en que el solicitante sea único en su tabla, gracias por tu respuesta, pero no debo separar el formulario debe estar todo completo, existe alguna posibilidad de que con Yii al yo escribir la cédula, si el solicitante existe me cargue los demás datos en el formulario y me bloquee los campos de texto (solo los del solicitante) y que a la hora de guardar, como ya existe me guarde solo los datos de la solicitud con el id del solicitante que estoy trayendo de la base de datos a través de la cédula?

Eso lo puedes lograr a través de una llamada ajax. Mi preferencia es usar un botón de búsqueda en lugar de hacerla directamente del textField porque cualquier error en la entrada sería considerado como un nuevo solicitante. En una aplicación de récords médicos que completé el año pasado hice lo siguiente:

(usando la notación de YiiBootstrap)




<?php echo $form->textFieldRow($modelPatient,'patient2lookup',array(

        'id'=>'pidinput',

        'placeholder'=>'# Récord o Apellidos,Nombre',

        'prepend'=>'<i class="icon-search"></i>',

    ));

    echo '&nbsp;&nbsp;';

    $this->widget('bootstrap.widgets.TbButton', array(

	'id' => 'lookup-btn',

        'type'=>'info',

	'buttonType' => 'ajaxButton',

	'icon'=>'icon-search',

	'label'=>'Buscar',

        'size'=>'small',

        'url'=>$this->createUrl('fetchpatient'),

        'ajaxOptions'=>array(

            'type'=>'POST',

            'dataType'=>'json',

            'data'=>array('patient2lookup'=>'js:$("#pidinput").val()'),

            'success'=>'js:function(data){

                if (isArray(data) && data.length > 0)

                {

                    for (var i in data)

                    {

                        var hrecnum = data[i].healthrecord_number;

                        $("#patientdata").append("<div class=\"hrlink\" id=" + hrecnum + ">" +

                            hrecnum.link("#") + "  " + data[i].patientname + "</div>"

                        );

                    }

                }

                else if (data.length != 0)

                {

                    $("#Referral_patient_id").val(data.id);

                    $("#pidinput").val(data.last_name + ", " + data.first_name);

                    $("#patientdata").html(data.healthrecord_number+"<br>"+data.patientage+"<br>"+data.sex+"<br>"+data.telephone);

                }

                else

                {

                    $("#patientdata").html("¡NO ENCONTRE AL PACIENTE!");

                }

                $("#patientdata").show();

            }',

	),

    ));

    echo '&nbsp;&nbsp;';

    $this->widget('bootstrap.widgets.TbButton', array(

	'id' => 'reset-btn',

	'buttonType' => 'reset',

	'label'=>'Reset',

        'size'=>'small',

    ));

    ?>

    <?php echo $form->hiddenField($model,'patient_id'); ?>

    <div id="patientdata" class="patientbox" style="display:none"></div>



El código inmediatamente debajo de "if (isArray(data) && data.length > 0)" maneja los casos donde la búsqueda por nombre tiene más de un resultado (LIKE en la base de datos). El URL "fetchpatient" es una acción en el controlador que devuelve resultados formateados en JSON. Adentro de la función "success" puedes activar/desactivar los campos que desees basados en los resultados recibidos. El hiddenField provee la llave primaria del paciente para ser enviado en el submit y poblar la llave foránea del referido. En el caso que el paciente no exista previamente entonces el usuario debe crearlo primero, por lo cual yo lo obligo a hacerlo en una acción separada pero se puede programar para activar una ventana modal que lo facilite.

Eres un genio en esto xD, la verdad no entendí mucho porque recién estoy empezando con Yii y no soy un experto en Ajax, tratare de adaptarlo a lo que quiero muchas gracias

Jejeje, gracias por lo de genio pero no, qué vá… :P Sólo tengo un poco más de experiencia con Yii que tú, pero apuesto que con el tiempo estarás en posición de ayudar a novatos.

Buena suerte,

P.D. Por si te ayuda, aquí esta la accion "fetchpatient" del controlador:




/**

     * Finds a patient by health record number or last,first name.

     */

    public function actionFetchpatient()

    {

        $modelPatient = new Patient;

        

        if(!empty($_POST['patient2lookup']))

        {

            if(!strpos($_POST['patient2lookup'], ',') === false)   // if comma present, then by last,first name

            {

                list($lname, $fname) = explode(',', $_POST['patient2lookup']);

                $modelPatient->last_name = trim($lname);

                $modelPatient->first_name = trim($fname);

            }

            else    // single entry (no comma) then by health record number

                $modelPatient->healthrecord_number = $_POST['patient2lookup'];

            

            $modelPatient = $modelPatient->lookup(); // lookup patient in model method

            

            if(!empty($modelPatient))

            {

                 // only one patient found

                if($modelPatient->totalItemCount == 1)

                {

                   // echo '<pre>'.CVarDumper::dumpAsString($modelPatient->data).'</pre>';

                    echo CJSON::encode(array(

                        'id'=>$modelPatient->data['0']->id,

                        'healthrecord_number'=>'# Récord: '.$modelPatient->data['0']->healthrecord_number,

                        'last_name'=>$modelPatient->data['0']->last_name,

                        'first_name'=>$modelPatient->data['0']->first_name,

                        'patientname'=>$modelPatient->data['0']->patientname,

                    ));

                }

                else

                {

                    echo CJSON::encode(Utils::convertModelToArray($modelPatient->data,array(

                        'Patient'=>'id, healthrecord_number, last_name, first_name'

                    )));

                }

            }

            else

                echo CJSON::encode(array(

                        'id'=>'',

                        'healthrecord_number'=>'',

                        'last_name'=>'¡NO ENCONTRE AL PACIENTE!',

                        'first_name'=>'',

                ));

        }

    }



La función convertModelToArray la encontré aquí.

Como ves, todos dependemos de todos si deseamos progresar y nos ayudamos mutuamente.