[Solved]Insert In 2 Tables With 1 Form

Good afternoon.

I’ve the following:

[color="#0000FF"]

*** 3 tables ***[/color]

  • Authors (IdAuthor, AuthorName)

  • Books (IdBook, BookName)

  • Authors_Books (IdAuthor, IdBook)

[color="#0000FF"]*** 2 models ***[/color]

  • Authors

  • Books

A books can have multiple authors.

In my Books view, I’ve a form with a dropdownlist for Authors.AuthorName and a textarea for Books.BookName.

I want:

1- Put 2 buttons (Add and Remove) and a CListView in the Books view’s form. When I click on Add button, the Author selected in dropdownlist will be added to a bottom listview. When I click on Remove button, the author selected in listview will be removed from listview.

2- I want to save data in the Books table, and then I want save the data in the Authors_Books table (both in actionCreate in Books controller). From what I’ve read, I think I have to make a new model for Authors_Books and use it. But, should not this model have a controller?

How I can implement this?

I need help.

Thanks.

you can save into 2 Models(tables) with the controller you are working with.

but you need to have the model for every table you want to perform operations with in order to communicate with database.

–cheers

Hope this helps a bit. its rough idea to get on…


public function actionCreate()

	{

		$model1=new Model1;

		

		$model2  = Model2::model()->findAll();


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

		{

			//var_dump($_REQUEST);die;

			


				if($model->save()){

					//save the record into Model2

					$model2->model1_id  = $model->id;

					

					$model2->model1_name_  = $_POST['Model3']['name'];

					$model2->save();

					


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

				'model1'=>$model1,

				'model2'=>$model2,

				'another3'=>anotherModel::model()->findAll(),


		));


	}




dont mind if you find any errors…

Thanks for the clarification, developer!.

But i don’t understand your code very well.

  • $model1-> Is it Books model?

  • $model2-> Is it Authors model?

  • Should not write this


$model1->attributes=$_POST['Model1'];

before save?

  • I don’t understand the code that comes after

if($model->save()){



.

I’ll try and I commented.

Thanks for the replies.

yes $model1 is like Books model.

But you have a model book, isn’t? in your folder model.

so at the place of $model1 you write $books, so after the code is :

yes you should do that before saving :




$books->attributes=$_POST['books']



if you save 2 models you can do a transaction, I have a exemple for you :




public function actionCreate() {

        $model = new PePersonne;

        $modelAdresse = new PeAdresse;

        $adresseCreation = false;

        // Uncomment the following line if AJAX validation is needed

        $this->performAjaxValidation(array($model, $modelAdresse));

        

        if (isset($_POST['PeAdresse']) || isset($_POST['PePersonne'])) {

            $transaction = $model->dbConnection->beginTransaction();

            try {

                if (isset($_POST['PeAdresse'])) {

                    $modelAdresse->attributes = $_POST['PeAdresse'];

                    $valid = $modelAdresse->validate();


                    if ($valid && PeAdresse::AdresseIsSet($modelAdresse->attributes)) {

                        $modelAdresse->adresse_id = PeAdresse::getNewUID();

                        $modelAdresse->save();

                        $adresseCreation = true;

                    }

                }

                if (isset($_POST['PePersonne'])) {

                    

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

                    $valid = $model->validate();

                    if ($valid) {

                        if ($adresseCreation) {

                            $model->fk_adresse_priv = $modelAdresse->adresse_id;

                        }

                        $model->personne_id = PePersonne::getNewUID();

                        $model->fk_type_pers = UTILISATEUR;

                        $model->save();

                    }

                }

                // gestion des profils

                if (!empty($_POST['PePersonne']['listProfils'])){                  

                    AdPersonneProfil::model()->deleteAll(array('condition' => 'fk_personne=:personneId', 'params' => array(':personneId' => $model->personne_id)));

                    foreach ($_POST['PePersonne']['listProfils'] as  $value) {          

                        $modelProfil = new AdPersonneProfil;                       

                        $modelProfil->fk_profil = $value;                        

                        $modelProfil->fk_personne = $model->personne_id;                      

                        $modelProfil->save();

                    }

                       

                }

                // FIN -- gestion des profils

 

                $transaction->commit();

                Yii::app()->user->setFlash('messageToDisplay', yii::t('messages', 'okCreation'));

                $this->redirect(array('admin', 'id' => $model->personne_id));

            } catch (Exception $e) {

                $transaction->rollback();

                Yii::app()->user->setFlash('messageToDisplay', yii::t('messages', 'erreurCreation'));

            }

        }


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

            'model' => $model,

            'modelAdresse' => $modelAdresse,

        ));

    }



yon can use $model->save(); for create and update.

as you did $books->attributes=$_POST[‘books’], $model->save() will create or update your table books with new values.

I hope I have help you even if my english is very bad !

Good morning!!

Thanks for replies!

Thanks to them and to this thread Multiple Models I get save the data.

But still not working as I want.

1- The data is saved correctly, but I need a list with buttons for adding and removing some IdAuthors in Authors_Books table.

2- When I update the data, I have to re-pass all three models to update form, how is it right?

3- In admin form I must show all AuthorName related with IdBook, and I don’t display them.

My code:

BooksController:


public function actionCreate()

    {

$modelBooks=new Books;       

        $modelAB=new AuthorsBooks();          

        $modelAuthors=new Authors;     

        

        if (isset($_POST['Books']) || 

                isset($_POST['AuthorsBooks']))

        {

            $transaction = $Books->dbConnection->beginTransaction();

            

            try 

            {

                $Books->attributes=$_POST['Books'];


                if($Books->save())            

                {

                    $AuthorsBooks->attributes=$_POST['AuthorsBooks'];

                    $AuthorsBooks->IdBook=$Books->IdBook;

                    

                    if($AuthorsBooks->save())

                    {

                        $transaction->commit();

                        $this->redirect(array('view','id'=>$Books->IdBook));

                    }

                }

            } catch (Exception $e) {

                $transaction->rollback();

                Yii::app()->user->setFlash('Error.', yii::t('messages', 'erreurCreation'));

            }

        }

        

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

                                    'Books'=>$Books,

                                    'AuthorBooks'=>$AuthorBooks,

                                    'Authors'=>$Authors,

                    ));

}


public function actionUpdate($id)

    {

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


        // Uncomment the following line if AJAX validation is needed

        // $this->performAjaxValidation($model);


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

        {

            $Books->attributes=$_POST['Books'];

            

            if($Books->save())

                $this->redirect(array('view','id'=>$Books->IdBooks));

        }


        $this->render('update',array('Books'=>$Books,));

}

Books model:




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(

                    'FK_MPA_books' => array(self::MANY_MANY, 'Authors', 

                                                    'Authors_Books(IdBook, IdAuthor)'),

        );

    }


public function search()

    {

        // Warning: Please modify the following code to remove attributes that

        // should not be searched.


        $criteria=new CDbCriteria;

        

        $criteria->with = array('FK_MPA_books');           

        $criteria->compare('FK_MPA_books',$this->IdAuthor);

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


        return new CActiveDataProvider($this, array(

                                                    'criteria'=>$criteria,

        ));

    }



AuthorsBooks model:




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(

        );

    }

Authors model:




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(

                    'FK_Authors' => array(self::MANY_MANY, 'Books', 'Authors_Books(IdAuthor, IdBook)'),

        );

    }

"_form.php" Books:




<div class="row">

            <?php 

                echo $form->labelEx($AuthorsBooks,'IdAuthor'); 

                echo $form->dropDownList($AuthorsBooks, 'IdAuthor', CHtml::listData(

                                        AuthorsBooks::model()->findAll(), 'IdAuthor', 'AuthorName'),

                                        array('prompt' => 'Select')); 

                echo $form->error($AuthorsBooks,'IdAuthor'); 

            ?>

        </div>

"update.php" Books:




echo $this->renderPartial('_form', array('Books'=>$Books)); 

"admin.php" Books:




    $this->widget('application.components.GridView', array(

                        'id'=>'books-grid',

                        'dataProvider'=>$model->search(),

                        'filter'=>$model,

                        'columns'=>array(

                                        array('name'=>'IdAuthor', 

                                                'value'=>'(isset($data->FK_MPA_books->IdAuthor)) ? 

                                                            $data->FK_MPA_books->IdAuthor : ""' ),

                                        'BookName',

                                        array('class'=>'CButtonColumn',),

                                    ),

    )); 

I will try things to see if I succeed. Any help is welcome, lol.

Thanks.

Good morning again!

Well, after I following this example Example, I got almost what I want.

But the AJAX code fail.

When I click in gridview A, I get an error: “Request failed: error.” and I don’t know why. Therefore, the B gridview doesn’t refresh.

Here my code:

views/Books/admin.php




<?php

    /* @var $this BooksController */

    /* @var $model Books */


    $this->breadcrumbs=array(

                            'Books'=>array('index'),

                            'Manage',

    );


    $this->menu=array(

                    array('label'=>'List', 'url'=>array('index')),

                    array('label'=>'New', 'url'=>array('create')),

    );


    Yii::app()->clientScript->registerScript('search', "

                                            $('.search-button').click(function(){

                                                    $('.search-form').toggle();

                                                    return false;

                                            });

                                            $('.search-form form').submit(function(){

                                                    $.fn.yiiGridView.update('books-grid', {

                                                            data: $(this).serialize()

                                                    });

                                                    return false;

                                            });

    ");

?>


<h1>Manage Books</h1>


<div class="span-5 last operations_ads">

    <div id="sidebar">

        <?php

            $this->widget('zii.widgets.CMenu', array(

                                                    'items'=>$this->menu,

                                                    'htmlOptions'=>array('class'=>'operations'),

            ));

        ?>

    </div><!-- sidebar -->

</div>


<?php 

    echo CHtml::link('Advanced Search','#',array('class'=>'search-button')); 

?>


<div class="search-form" style="display:none">

    <?php 

        $this->renderPartial('_search',array('modelBooks'=>$modelBooks,)); 

    ?>

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


<div id="parentView">

    <?php 

        $this->widget('application.components.GridView', array(

                'id'=>'books-grid',

                'dataProvider'=>$modelBooks->search(),

                'filter'=>$modelBooks,

                'columns'=>array(

                                'IdBook',

                                'Book',

                                array('class'=>'CButtonColumn',),

                            ),

                'ajaxUpdate' => 'child-grid',

        )); 

    ?>

</div>


<!-- Use this paragraph to display the loading.gif icon above the Child Gridview,

while waiting for the ajax response -->

<p id="loadingPic"></br></p>


<!-- The childView <div>, renders the _child form, which contains the Child Gridview.

The ajax response will replace/update the whole <div> and not just the gridview. -->

<div id="childView">

    <?php

        $this->renderPartial('_child', array(

                                            'modelAuthorsBooks' => $modelAuthorsBooks, /* New */

                                            'IdBook' => $IdBook, /* New */

        ))

    ?>

</div>


<?php

    /*Load the javascript file that contains the ajax function*/

    $path = Yii::app()->baseUrl.'/js/customFunctions.js';

    Yii::app()->clientScript->registerScriptFile($path, CClientScript::POS_END);

?>



views/Books/_child.php




<p id="subsectionheading">Related Authors</p>

<div class="hint">(Please note: If no Book is selected, the Authors of the top-most Book are displayed.)</div>

 

<?php

    $this->widget('application.components.GridView', array(

                            'id'=>'child-grid',

                            'dataProvider'=>$modelAuthorsBooks->searchIncludingAuthors($IdBook),

                            'filter'=>$modelAuthorsBooks,

                            'columns'=>array(

                                            array(

                                                'name'=>'AuthorName',

                                                'value'=>'($data->FK_AB_Authors)?$data->

                                                    FK_AB_Authors->AuthorName:""', 

                                                    /* Test for empty related fields not to crash the 

                                                     * program */

                                                'header'=>'Author Name',

                                                'filter' => CHtml::activeTextField($modelAuthorsBooks,'AuthorName'),

                                            ),

                                            array(

                                                'class'=>'CButtonColumn',

                                                'template'=>'{view}{update}{delete}',

                                                'viewButtonUrl' => 'array("Authors/view",

                                                "id"=>$data->IdAuthor)',

                                                'updateButtonUrl' => 'array("Authors/update",

                                                "id"=>$data->IdAuthor)',

                                                'deleteButtonUrl' => 'array("Authors/delete",

                                                "id"=>$data->IdAuthor)',

                ),

    ),

));

?>



controllers/BooksController.php




public function actionAdmin()

    {

        $modelBooks=new Books('search');

        $modelBooks->unsetAttributes();  

        

        if(isset($_GET['Books']))

            $modelBooks->attributes=$_GET['Books'];

        

        if(!isset($_GET['IdBook']))

        {

            $group = "A";


            $criteria=new CDbCriteria;

 

            $criteria->compare('IdBook',$modelBooks->IdBook,true);

            $criteria->compare('BookName',$modelBooks->BookName,true);

 

            $dataProvider = new CActiveDataProvider('Books', 

                                                        array(

                                                            'criteria'=>$criteria,

                ));

 

            /* Test if the dataProvider found any data (filtering 

                parameters might have excluded all records)*/

            If (count($dataProvider->getData()) > 0) 

            {

                /* Extract the first model from the dataprovider */

                $first_model=$dataProvider->getData();

 

                /* Extract the record's PK, to be used to generate 

                the child-gridview's data records.*/

                $IdBook= $first_model[0]->IdMedicamento;

            }

            else

            {

                /* Set $IdBook to 0, to return an empty child-

                grid.*/

                $IdBook= 0;

            }

        }

        else

        {

            /* The event using this action, is from Group B: */

            $group = "B";

 

            /* Get the IdBook, which the event passed to this 

            action.*/

            $IdBook= $_GET['IdBook'];

        }

        

        $modelAuthorsBooks = new AuthorsBooks("searchIncludingAuthors($IdBook)");

        $modelAuthorsBooks ->unsetAttributes();

        $modelAuthorsBooks ->scenario = 'searchIncludingAuthors';

        

        if(isset($_GET['AuthorsBooks']))

            $modelAuthorsBooks ->attributes=$_GET['AuthorsBooks'];

        

        if($group == "A"){

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

                'modelBooks'=>$modelBooks,

                'modelAuthorsBooks '=>$modelAuthorsBooks ,

                'IdBook' => $IdBook,

            ));

        }

        else{

            $this->renderPartial('_child', array(

                'modelAuthorsBooks '=>$modelAuthorsBooks ,

                'IdBook' => $IdBook,

            ));

        }

    }




AuthorsBooks model




    public $AuthorName; 


    public function rules()

    {

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

        // will receive user inputs.

        return array(

                    array('IdAuthor, IdBook', 'required'),

                    array('IdAuthor, IdBook', 'numerical', 'integerOnly'=>true),

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

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

                    array('AuthorName, IdBook', 'safe', 'on'=>'search, 

                            searchIncludingAuthors'),

        );

    }


    /**

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

            'FK_AB_Books' => array(self::BELONGS_TO, 'Books', 'IdBook'),

            'FK_AB_Authors' => array(self::BELONGS_TO, 'Authors', 

                                                'IdAuthor'),

        );

    }


public function search()

    {

        // Warning: Please modify the following code to remove attributes that

        // should not be searched.


        $criteria=new CDbCriteria;


        $criteria->compare('IdAuthor',$this->IdAuthor);

        $criteria->compare('IdBook',$this->IdBook);


        return new CActiveDataProvider($this, array(

                                                    'criteria'=>$criteria,

        ));

    }

    

    public function searchIncludingAuthors($IdBook)

    {

        /* This function creates a dataprovider with RolePermission

        models, based on the parameters received from the controller. It

        also includes related Permission models, obtained via the

        relPermission relation. */

        $criteria=new CDbCriteria;

        $criteria->with=array('FK_AB_Authors');

        $criteria->together = true;

 

 

        /* filter on books-grid PK ($IdBook) received from the 

        controller*/

        $criteria->compare('t.IdBook',$IdBook,false); 

 

        /* Filter on default Model's column if user entered parameter*/

        $criteria->compare('t.IdAuthor',$this->IdAuthor,true);

 

        /* Filter on related Model's column if user entered parameter*/

        $criteria->compare('FK_AB_Authors.AuthorName',

            $this->AuthorName,true);

 

        /* Sort on related Model's columns */

        $sort = new CSort;

        $sort->attributes = array(

            'AuthorName' => array(

            'asc' => 'AuthorName',

            'desc' => 'AuthorName DESC',

            ), '*', /* Treat all other columns normally */

        );

        /* End: Sort on related Model's columns */

 

        return new CActiveDataProvider($this, array(

            'criteria'=>$criteria,

            'sort'=>$sort, /* Needed for sort */

        ));

    }



AJAX–customFunctions.js




$('#parentView').on("click", "table tbody td:not(td:.button-column)", function(event){

    

    try{

        /*Extract the Primary Key from the CGridView's clicked row.

        "this" is the CGridView's clicked column or <td>.

        Go up one parent - which gives you the row.

        Go down to child(1) - which gives you the first column,

            containing the row's PK. */

        var gridRowPK = $(this).parent().children(':nth-child(1)').text();

        /*Display the loading.gif file via jquery and CSS*/

        $("#loadingPic").addClass("loadGIF");

 

        /* Call the Ajax function to update the Child CGridView via the

        controller’s actionAdmin */

        var request = $.ajax({ 

          url: "Admin",

          type: "GET",

          cache: false,

          data: {IdMedicamento : gridRowPK},

          dataType: "html" 

        });

 

        request.done(function(response) { 

            try{

                /*since you are updating innerHTML, make sure the

                received data does not contain any javascript - 

                for security reasons*/

                if (response.indexOf('<script') == -1)

                {

                    /*update the view with the data received 

                    from the server*/       

                    document.getElementById('childView').innerHTML = response;

                }

                else 

                {

                    throw new Error('Invalid Javascript in Response - possible hacking!');

                }

            }

            catch (ex){

                alert(ex.message); /*** Send this to the server 

                for logging when in production ***/

            }

            finally{

                /*Remove the loading.gif file via jquery and CSS*/

                $("#loadingPic").removeClass("loadGIF");

 

                /*clear the ajax object after use*/

                request = null;

            };

        });


        request.fail(function(jqXHR, textStatus) {

            try{

                throw new Error('Request failed: ' + textStatus );

            }

            catch (ex){

                alert(ex.message); /*** Send this to the server 

                for logging when in production ***/

            }

            finally{

                /*Remove the loading.gif file via jquery and CSS*/

                $("#loadingPic").removeClass("loadGIF");

 

                /*clear the ajax object after use*/

                request = null;

            }

        });

    }

    catch (ex){

        alert(ex.message); /*** Send this to the server for logging when 

        in production ***/

    }

});



AJAX fails in line


request.done(function(response) { 

It’s what I need to get it!!. I need ideas!

Thanks.

Finally revolved.

I did following this Example for refresh the chil CGridView and go.

Thanks you all!!