Ayuda con ActiveRecord y Claves

Hola a todos, estoy empezando a trabajar con yii, y tengo un problema con los registros.

Tengo las siguientes tablas :

proyecto

PRY_Id (PK)

pequerimiento

REQ_Id (PK)

PRY_Id (PK)(FK)

–en el modelo

public function relations()

{





	return array(


		'pRY' => array(self::BELONGS_TO, 'proyecto', 'PRY_Id'),





	);


}

Cuando PRY_Id en la tabla requerimiento es solo FK, trabaja bien, pero cuando es además PK me produce un error. Agradecería cualquier ayuda o ejemplo de como trabajar con este tipo de tablas

que error te produce ?

Buenas te voy a explicar como lo hago yo, igual es una chapuza pero bueno…

Mis tablas son las que anexo, pero la que te interesa es la de rel_mancomunidades_municipios ya que es una tabla de relaciones entre dos tablas y por tanto tiene esas id como PK compuesta.

Primero el modelo:

==================




class RelMancomunidadesMunicipios extends CActiveRecord

{

	/**

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

	 * @var integer $id_mancomunidad

	 * @var integer $id_municipio

	 * @var string $fecha_anexion

	 * @var string $fecha_baja

	 */


	/**

	 * Returns the static model of the specified AR class.

	 * @return CActiveRecord the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}


	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'rel_mancomunidades_municipios';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		return array(

			array('id_mancomunidad, id_municipio, fecha_anexion', 'required'),

                        array('id_mancomunidad, id_municipio', 'numerical', 'integerOnly'=>true),

                        array('fecha_baja', 'safe'),

		);

	}


	/**

	 * @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(

                    'mancomunidades' => array(self::BELONGS_TO, 'Mancomunidades', 'id_mancomunidad','alias'=>'mancomunidades'),

                    'municipios' => array(self::BELONGS_TO, 'Municipios', 'id_municipio','alias'=>'municipios'),

		);

	}


	/**

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

	 */

	public function attributeLabels()

	{

		return array(

			'id_mancomunidad' => 'Mancomunidad',

			'id_municipio' => 'Municipio',

			'fecha_anexion' => 'Fecha Anexion',

			'fecha_baja' => 'Fecha Baja',

		);

	}

}



El formulario para dicho modelo:

================================




<div class="yiiForm">


<p>

Campos con <span class="required">*</span> son obligatorios.

</p>


<?php echo CHtml::beginForm('','post',array('id'=>'RelMancomunidadesMunicipios')); ?>


<?php echo CHtml::errorSummary($model); ?>


<div class="texto_error_login ui-corner-all" id="errores_relmancomunidadmunicipio" style="visibility:hidden"></div>


<div class="simple">

<?php echo CHtml::activeHiddenField($model,'id_mancomunidad'); ?>

</div>


<div class="simple">

<?php echo CHtml::activeLabelEx($model,'id_municipio'); ?>

<?php echo CHtml::activeDropDownList($model,'id_municipio',CHtml::listdata(Municipios::model()->findAll(),'id','nombre')); ?>

</div>


<div class="simple">

<?php echo CHtml::hiddenField('RelMancomunidadesMunicipios[id_municipio_anterior]','',array('id'=>'RelMancomunidadesMunicipios_id_municipio_anterior')); ?>

</div>


<div class="simple">

<?php echo CHtml::activeLabelEx($model,'fecha_anexion'); ?>

<?php echo CHtml::activeTextField($model,'fecha_anexion'); ?>

</div>


<div class="simple">

<?php echo CHtml::activeLabelEx($model,'fecha_baja'); ?>

<?php echo CHtml::activeTextField($model,'fecha_baja'); ?>

</div>


<?php

if ((Yii::app()->user->grupo)=="Administración") {

?>

<div class="ui-helper-clearfix">

    <ul class="buttons ui-widget">

        <li class="ui-state-default ui-corner-all" id="relmancomunidadesmunicipios_crud_create" style="visibility:visible">

            <span class="ui-icon ui-icon-document"></span>Crear registro

        </li>

        <li class="ui-state-default ui-corner-all" id="relmancomunidadesmunicipios_crud_update" style="visibility:visible">

            <span class="ui-icon ui-icon-document"></span>Actualizar registro

        </li>

    </ul>

</div>


<script type="text/javascript">

    jQuery(document).ready(function() {


        jQuery('#relmancomunidadesmunicipios_crud_create').unbind('click').click(function(){

            jQuery.ajax({

                'dataType':'json',

                'success':function(response) {

                    //successAjaxCRUD('errores_mancomunidad_municipio',response);

                    if (response.result=="OK") {

                        successAjaxCRUD('errores_mancomunidades_municipios',response);

                        //$('#pts_grid').trigger("reloadGrid");

                        $('#formRelMancomunidadesMunicipios').dialog('close');

                        $('#RelMancomunidadesMunicipios').clearForm();

                        rellenar_ficha_municipios($("#Mancomunidades_id").attr("value"));

                    } else if (response.result=="KO") {

                        //$('#pts_grid').trigger("reloadGrid");

                        successAjaxCRUD('errores_relmancomunidadmunicipio',response);

                    }

                },

                'error':function(request, error, thrownError){

                    errorAjaxCRUD('errores_relmancomunidadmunicipio',request,error,thrownError);

                },

                'type':'POST',

                'url':'/aurora/index.php?r=infoGestionGeografica/createRelMancomunidadMunicipio',

                'cache':false,

                'data':jQuery(this).parents("form").serialize()

            });

            return false;

        });


        jQuery('#relmancomunidadesmunicipios_crud_update').unbind('click').click(function(){

            jQuery.ajax({

                'dataType':'json',

                'success':function(response) {

                    if (response.result=="OK") {

                        successAjaxCRUD('errores_mancomunidades_municipios',response);

                        //$('#pts_grid').trigger("reloadGrid");

                        $('#formRelMancomunidadesMunicipios').dialog('close');

                        $('#RelMancomunidadesMunicipios').clearForm();

                        rellenar_ficha_municipios($("#Mancomunidades_id").attr("value"));

                    } else if (response.result=="KO") {

                        //$('#pts_grid').trigger("reloadGrid");

                        successAjaxCRUD('errores_relmancomunidadmunicipio',response);

                    }

                },

                'error':function(request, error, thrownError){

                    errorAjaxCRUD('errores_relmancomunidadmunicipio',request,error,thrownError);

                },

                'type':'POST',

                'url':'/aurora/index.php?r=infoGestionGeografica/updateRelMancomunidadMunicipio',

                'cache':false,

                'data':jQuery(this).parents("form").serialize()

            });

            return false;

        });


    });

</script>

<?php

}

?>


<?php echo CHtml::endForm(); ?>


</div><!-- yiiForm -->



Como ves en el formulario hago todo por AJAX usando JQuery por lo que esa parte no la tienes que tener en cuenta.

Controlador (las acciones de Create, Update y Delete):

======================================================




    public function actionCreateRelMancomunidadMunicipio() {

        $model=new RelMancomunidadesMunicipios();

        $model->setScenario('create');


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

        {

            if ($_POST['RelMancomunidadesMunicipios']['fecha_baja']=="") {

                $_POST['RelMancomunidadesMunicipios']['fecha_baja']="0000-00-00";

            }

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


            $responce=new FormJson();


            if($model->save(true)) {

                $responce->result="OK";

                $responce->rows[0]['descripcion']="Se ha creado el registro correctamente.";

            } else {

                $arr_errores=$model->getErrors();


                $responce->result="KO";


                $i=0;

                foreach ($arr_errores as $errores=>$error) {

                    foreach ($error as $key=>$value) {

                        $responce->rows[$i]['campo']=$errores;

                        $responce->rows[$i]['descripcion']=$value;

                    }

                    $i++;

                }

            }


            echo json_encode($responce);

        }

    }


    public function actionUpdateRelMancomunidadMunicipio() {

        $model=new RelMancomunidadesMunicipios();

        $model->setScenario('update');


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

        {

            $model=RelMancomunidadesMunicipios::model()->findByPk(array('id_mancomunidad'=>$_POST['RelMancomunidadesMunicipios']['id_mancomunidad'], 'id_municipio'=>$_POST['RelMancomunidadesMunicipios']['id_municipio_anterior']));

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


            $responce=new FormJson();


            if($model->save(true)) {

                $responce->result="OK";

                $responce->rows[0]['descripcion']="Se ha actualizado el registro correctamente.";

            } else {

                $arr_errores=$model->getErrors();


                $responce->result="KO";


                $i=0;

                foreach ($arr_errores as $errores=>$error) {

                    foreach ($error as $key=>$value) {

                        $responce->rows[$i]['campo']=$errores;

                        $responce->rows[$i]['descripcion']=$value;

                    }

                    $i++;

                }

            }


            echo json_encode($responce);

        }

    }


    public function actionDeleteRelMancomunidadMunicipio() {

        $model=new RelMancomunidadesMunicipios();

        $model->setScenario('update');


        if(isset($_GET['id_mancomunidad'])&& isset($_GET['id_municipio']))

        {

            $responce=new FormJson();


            $borrado=RelMancomunidadesMunicipios::model()->deleteByPk(array('id_mancomunidad'=>$_GET['id_mancomunidad'],'id_municipio'=>$_GET['id_municipio']));


            if($borrado==1) {

                $responce->result="OK";

                $responce->rows[0]['descripcion']="Se ha realizado el borrado del registro correctamente.";

            } else {

                $arr_errores=$model->getErrors();


                $responce->result="KO";


                $i=0;

                foreach ($arr_errores as $errores=>$error) {

                    foreach ($error as $key=>$value) {

                        $responce->rows[$i]['campo']=$errores;

                        $responce->rows[$i]['descripcion']=$value;

                    }

                    $i++;

                }

            }


            echo json_encode($responce);

        }

    }



Aquí tampoco hagas caso del objeto $response que es un Json que tengo para el resultado de la acción ya que te recuerdo que yo lo hago por AJAX.

Para hacerlo sin AJAX simplemente tienes que tener el botón de submit y enviar el formulario a la acción correspondiente según lo que quieras hacer.

Mira el código a ver si te sirve.

Saludos.

Se me olvidaba!!!

Aunque el Yii te cree automaticamente el modelo, formulario y acciones del controlador, debes retocarlas con código tuyo para dejarlo como tu quieres que funcione.

Saludos.

CDbCommand falló al ejecutar la sentencia SQL: SQLSTATE[HY000]: General error: 1452 Cannot add or update a child row: a foreign key constraint fails (BDatos.requerimiento, CONSTRAINT fk_requerimiento_proyecto1 FOREIGN KEY (PRY_Id) REFERENCES proyecto (PRY_Id) ON DELETE NO ACTION ON UPDATE NO ACTION)

Sagitta. alteré la parte de las relaciones, como las definiste en tu codigo… pero igual sigue el problema al guardar

lo q tengo en el modelo:

$model= new requerimiento();

if(isset(&#036;_POST[requerimiento]))


{


&#036;model-&gt;attributes=&#036;_POST['requerimiento'];


        


    &#036;model-&gt;save();


    &#036;this-&gt;render('index',array('model'=&gt;&#036;model));

}

CDbCommand falló al ejecutar la sentencia SQL: SQLSTATE[HY000]: General error: 1452 Cannot add or update a child row: a foreign key constraint fails (BDatos.requerimiento, CONSTRAINT fk_requerimiento_proyecto1 FOREIGN KEY (PRY_Id) REFERENCES proyecto (PRY_Id) ON DELETE NO ACTION ON UPDATE NO ACTION)

Sagitta. alteré la parte de las relaciones, como las definiste en tu codigo… pero igual sigue el problema al guardar

Estas son mis tablas relacionadas:

1130

tablas.JPG

lo q tengo en el modelo:

$model= new requerimiento();

if(isset(&#036;_POST[requerimiento]))


{


&#036;model-&gt;attributes=&#036;_POST['requerimiento'];


        


    &#036;model-&gt;save();


    &#036;this-&gt;render('index',array('model'=&gt;&#036;model));


    }

alguna solución?

El ID de Proyecto que intentas meter en la tabla requerimiento existe previamente en la tabla proyecto???

Es que me parece que el error te lo está devolviendo el gestor de base de datos diciendo que no puede añadir un registro en la tabla requerimientos porque el id_proyecto no existe en la tabla padre de la relación, que es la tabla proyecto.

Puedes activar las trazas y ver que INSERT está intentando hacer en la BD y eso te da más información y puedes probar la consulta directamente en un programa cliente para la BD.

En el main.php yo tengo diferentes logs para las trazas:




'log'=>array(

                        'class'=>'CLogRouter',

                        'routes'=>array(

                                array(

                                        'class'=>'CFileLogRoute',

                                        'levels'=>'error',

                                        'logPath'=>Yii::getPathOfAlias('logsPath'),

                                        'logFile'=>date('Ymd').'-aplicacionName_error.log',

                                        'enabled'=>true,

                                ),

                                array(

                                        'class'=>'CFileLogRoute',


                                        'levels'=>'trace',

                                        'filter' => array(

                                            'class' => 'CLogFilter',

                                            'prefixSession' => true,

                                            'prefixUser' => true,

                                            'logUser' => true,

                                            'logVars' => array(),

                                        ),


                                        'logPath'=>Yii::getPathOfAlias('logsPath'),

                                        'logFile'=>date('Ymd').'-aplicacionName_trace.log',

                                        'enabled'=>true,

                                ),

                                array(

                                        'class'=>'CFileLogRoute',

                                        'levels'=>'info, warning',

                                        'filter' => array(

                                            'class' => 'CLogFilter',

                                            'prefixSession' => true,

                                            'prefixUser' => true,

                                            'logUser' => true,

                                            'logVars' => array(),

                                        ),

                                        'logPath'=>Yii::getPathOfAlias('logsPath'),

                                        'logFile'=>date('Ymd').'-aplicacionName.log',

                                        'enabled'=>true,

                                ),

                                array(

                                        'class'=>'CWebLogRoute',

                                        'levels'=>'trace',

                                        'filter'=>'CLogFilter',

                                        'enabled'=>true,

                                ),

                                array(

                                        'class'=>'CProfileLogRoute',

                                        //'levels'=>'trace',

                                        'enabled'=>true,

                                ),

                        ),

                ),



En la parte de arriba del main.php configuro la ruta del directorio de los logs:




Yii::setPathOfAlias( 'logsPath', dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'logs'.DIRECTORY_SEPARATOR);



En el archivo aplicacionName.log tendrás la traza que necesitas.

En la parte de la conexión a base de datos puedes añadir esta línea y ver las estadísticas de las consultas (en la parte de abajo de cada vista en el navegador:




'enableProfiling'=>true,



En el entorno de producción quita las trazas que no necesites (profiling, CProfileLogRoute, CWebLogRoute y la traza de nivel trace). La traza de aplicacionName.log puedes dejarla en el nivel warning solamente.

Saludos.

otra cosa. Según como lo tienes definido me imagino que la REQ_Id es autoincrementable en tabla requerimiento y PRY_Id es también autoincrementable en la tabla proyectos.

No te sobra que PRY_Id sea PK en la tabla requerimiento? simplemente con que sea FK te vale, no? Un requerimiento es para un proyecto… no? Ese requerimiento no lo vas a usar con otro proyecto si REQ_Id es ++, por lo tanto no tendrás dos registros con el mismo REQ_Id y el mismo PRY_Id.

Si puedes explicar un poco la relación que tienes puesta mejor para ver si está bien o mal lo que te digo arriba o por lo menos poder ayudarte mejor…

Hola gracias x responder.

En mi vista formulario, tengo un activeDropDownList que traba accediendo a la tabla proyecto, y mediante ese índice

es que hago la inserción




<td><?php echo $form->labelEx($model,'PRY_Id');?></td>

<td><?php echo CHtml::activeDropDownList($model,'PRY_Id',CHtml::listData(proyecto::model()->findAll(),'PRY_Id','PRY_Descripcion'));?></td>



Hola sagitta haciendo la traza estos son los resultados:

En el Application Log




$_GET=array (

  'r' => 'requerimiento',

)


$_POST=array (

  'requerimiento' => 

  array (

    'PRY_Id' => '75',

    'REQ_Fecha' => '2011/01/12',

  ),

  'yt0' => 'Grabar',

)



En el Profiling Summary Report :

Veo q se ejecuta esta sentencia




system.db.CDbCommand.execute(INSERT INTO `requerimiento` (`REQ_Fecha`) VALUES (:yp0))

system.db.CDbCommand.query(SHOW CREATE TABLE `requerimiento`)

system.db.CDbCommand.query(SHOW COLUMNS FROM `requerimiento`)



no inserta todos los datos.

Mira en el archivo log si has activado los logs que te he indicado antes. Es un nombreApp.log en el directorio de tu aplicación…

Ahí ves la sentencia real.

Hola gracias, ya pude resolver el problema, por alguna razón el parametro de PRY_Id que le enviava se perdía.

Agregué la siguiente linea:

[color="#FF0000"]$model->PRY_Id= $_POST[‘requerimiento’][‘PRY_Id’];[/color]

Así:




                $model= new requerimiento();

		if(isset($_POST[requerimiento]))

		{

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

                        $model->PRY_Id= $_POST['requerimiento']['PRY_Id'];

            

                       if($model->save())

                      {

                                                           

                      }

                     ...



Pues es raro porque si tienes dentro del formulario el activeDropDownList debería venirte el atributo en el submit del formulario y lo asociaría al modelo al hacer lo de $model->attributes.

¿Puedes pegar todo el código del formulario para verlo por curiosidad?

PD: para ver también las variables en las llamadas te recomiendo usar la extensión FireBug para el Firefox. Así podrás trazar lo que se envía en cada llamada y lo que se devuelve.